diff --git a/localized_fields/expressions.py b/localized_fields/expressions.py new file mode 100644 index 0000000..b0314b2 --- /dev/null +++ b/localized_fields/expressions.py @@ -0,0 +1,25 @@ +from django.conf import settings +from django.utils import translation + +from psqlextra import expressions + + +class LocalizedRef(expressions.HStoreRef): + """Expression that selects the value in a field only in + the currently active language.""" + + def __init__(self, name: str, lang: str=None): + """Initializes a new instance of :see:LocalizedRef. + + Arguments: + name: + The field/column to select from. + + lang: + The language to get the field/column in. + If not specified, the currently active language + is used. + """ + + language = lang or translation.get_language() or settings.LANGUAGE_CODE + super().__init__(name, language) diff --git a/localized_fields/fields/field.py b/localized_fields/fields/field.py index 2342c6a..a4071c7 100644 --- a/localized_fields/fields/field.py +++ b/localized_fields/fields/field.py @@ -82,6 +82,12 @@ class LocalizedField(HStoreField): return result + # this is for when you select an individual key, it will be string, + # not a dictionary, we'll give it to you as a flat value, not as a + # localized value instance + if not isinstance(value, dict): + return value + return cls.attr_class(value) def to_python(self, value: Union[dict, str, None]) -> LocalizedValue: diff --git a/tests/test_expressions.py b/tests/test_expressions.py new file mode 100644 index 0000000..a655f9a --- /dev/null +++ b/tests/test_expressions.py @@ -0,0 +1,65 @@ +from django.test import TestCase +from django.db import models +from django.utils import translation +from django.conf import settings + +from localized_fields.fields import LocalizedField +from localized_fields.value import LocalizedValue +from localized_fields.expressions import LocalizedRef + +from .fake_model import get_fake_model + + +class LocalizedExpressionsTestCase(TestCase): + """Tests whether expressions properly work with :see:LocalizedField.""" + + TestModel1 = None + TestModel2 = None + + @classmethod + def setUpClass(cls): + """Creates the test model in the database.""" + + super(LocalizedExpressionsTestCase, cls).setUpClass() + + cls.TestModel1 = get_fake_model( + 'LocalizedExpressionsTestCase2', + { + 'name': models.CharField(null=False, blank=False, max_length=255), + } + ) + + cls.TestModel2 = get_fake_model( + 'LocalizedExpressionsTestCase1', + { + 'text': LocalizedField(), + 'other': models.ForeignKey(cls.TestModel1, related_name='features') + } + ) + + @classmethod + def test_localized_ref(cls): + """Tests whether the :see:LocalizedRef expression properly works.""" + + obj = cls.TestModel1.objects.create(name='bla bla') + for i in range(0, 10): + cls.TestModel2.objects.create( + text=LocalizedValue(dict(en='text_%d_en' % i, ro='text_%d_ro' % i, nl='text_%d_nl' % i)), + other=obj + ) + + for lang_code, _ in settings.LANGUAGES: + translation.activate(lang_code) + + queryset = ( + cls.TestModel1.objects + .annotate( + mytexts=LocalizedRef('features__text') + ) + .values_list( + 'mytexts', flat=True + ) + ) + + for index, value in enumerate(queryset): + assert str(index) in value