Created
August 22, 2022 12:40
-
-
Save LeMinaw/cdc9c92113f5d5a0af067c5846e90f32 to your computer and use it in GitHub Desktop.
Custom manager for ordering Django QuerySets with modeltranslation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db.models import F, QuerySet | |
from django.db.models.functions import Coalesce | |
from modeltranslation.settings import AVAILABLE_LANGUAGES | |
from modeltranslation.utils import ( | |
build_localized_fieldname, get_language, resolution_order) | |
class MultilingualOrderQuerySet(QuerySet): | |
def coalesce_translations(self, field): | |
"""Coalesce all translations of a given field according to the | |
current language and fallback resolution order, and annotate | |
the current QuerySet with it through a `field_translations` key. | |
""" | |
# Languages the translation has to be searched in, in relevant | |
# order | |
langs = resolution_order( | |
get_language(), {'defaut': AVAILABLE_LANGUAGES} | |
) | |
# Build the list of translated fields names in relevant order | |
fields = [ | |
build_localized_fieldname(field, lang) for lang in langs | |
] | |
# If there is only one relevant field, no coalescing is needed | |
if len(fields) == 1: | |
annotation = F(fields[0]) | |
else: | |
# Get the underlying model field type | |
FieldType = self.model._meta.get_field(field).__class__ | |
# Annotate needs to know which type of field it has to output, | |
# because translated fields type differs from usual Django | |
# fields (e.g. TranslatedCharField differs from CharField) | |
annotation = Coalesce(*fields, output_field=FieldType()) | |
return self.annotate( | |
**{field + '_translations': annotation} | |
) | |
def order_by_translated(self, field): | |
"""As `modeltranslation` does not provide fallback values when | |
using the `order_by` method of its manager, this method | |
implements it. | |
It provides ordering with fallbacks, for a single translated | |
field only. | |
""" | |
return ( | |
self | |
.coalesce_translations(field.lstrip('-')) # Strip order | |
.order_by(field + '_translations') | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment