Skip to content

Instantly share code, notes, and snippets.

@LeMinaw
Created August 22, 2022 12:40
Show Gist options
  • Save LeMinaw/cdc9c92113f5d5a0af067c5846e90f32 to your computer and use it in GitHub Desktop.
Save LeMinaw/cdc9c92113f5d5a0af067c5846e90f32 to your computer and use it in GitHub Desktop.
Custom manager for ordering Django QuerySets with modeltranslation
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