django-modeltranslation icon indicating copy to clipboard operation
django-modeltranslation copied to clipboard

The MultilingualQuerySet class does not override annotation method

Open CefasR opened this issue 5 years ago • 1 comments

Consider the following case:

models.py file:

from django.db import models

class Object(models.Model):
    name = models.CharField()

translation.py file:

from modeltranslation.translator import TranslationOptions, register
from .models import Object

@register(Object)
class ObjectTranslationOptions(TranslationOptions):
    fields = ('name', )
    fallback_languages = {'default': ('en-us',)}

Current bahavior:

from .models import Object
from django.utils import translation
from django.db.models import F

translation.activate("pt-br")

Object.objects.ceate(name_en_us='Test', name_pt_br='Teste')

print(Object.objects.first().name) # prints 'Teste'
print(Object.objects.annotate(test_name=F('name')).first().test_name) # prints 'Test'

The expected behavior should be:

print(Object.objects.annotate(test_name=F('name')).first().test_name) # prints 'Teste'

CefasR avatar May 14 '20 21:05 CefasR

@CefasR I agree. I also encountered this issue. It would be awesome, if someone patched this. For now, since I also ran into this problem using F-expressions, I used this dirty hack:

from django.db.models.expressions import F
from django.utils.translation import get_language


class TranslatedF(F):
    def resolve_expression(self, query=None, allow_joins=True, reuse=None,
                           summarize=False, for_save=False, simple_col=False):
        lang = get_language().replace('-', '_')
        name = self.name + '_' + lang
        return query.resolve_ref(name, allow_joins, reuse, summarize, simple_col)

Then your annotation would oviously be:

print(Object.objects.annotate(test_name=TranslatedF('name')).first().test_name)  # prints 'Teste'

I chose to override the F.resolve_expression method to delay the get_language call as much as possible to have a better chance to resolve properly. The easier way would have been to override the F.__init__ method and simply replace the self.name attribute with the language-specific field name, but then the language would have to be defined during the F-object's initialization. Anyway, this worked for me in a specific situation. I couldn't figure out, where to even begin with a "proper" patch. Hope someone more skilled gets on that.

daniil-berg avatar Jul 13 '20 11:07 daniil-berg