django-localized-fields/tests/test_lookups.py
Swen Kooij e6527fff4c Don't double key transform in lookups
In Django 4.2, `process_lhs()` is called for IsNull lookups,
which is how this bug came to appear. It was already there
and could be reproduced on Django 3.2.

The issue is when `LocalizedRef` is combined with a localized
lookup. The lookup is unaware of the existing localized ref
and adds another transform on top. This results in the
expression becoming:

```
field->'en'->'en'
```
2024-07-02 07:10:41 +03:00

132 lines
4.5 KiB
Python

from django.apps import apps
from django.conf import settings
from django.test import TestCase, override_settings
from django.utils import translation
from localized_fields.expressions import LocalizedRef
from localized_fields.fields import LocalizedField
from localized_fields.value import LocalizedValue
from .fake_model import get_fake_model
@override_settings(LOCALIZED_FIELDS_EXPERIMENTAL=True)
class LocalizedLookupsTestCase(TestCase):
"""Tests whether localized lookups properly work with."""
TestModel1 = None
@classmethod
def setUpClass(cls):
"""Creates the test model in the database."""
super(LocalizedLookupsTestCase, cls).setUpClass()
# reload app as setting has changed
config = apps.get_app_config("localized_fields")
config.ready()
cls.TestModel = get_fake_model({"text": LocalizedField()})
def test_localized_lookup(self):
"""Tests whether localized lookup properly works."""
self.TestModel.objects.create(
text=LocalizedValue(dict(en="text_en", ro="text_ro", nl="text_nl"))
)
# assert that it properly lookups the currently active language
for lang_code, _ in settings.LANGUAGES:
translation.activate(lang_code)
assert self.TestModel.objects.filter(
text="text_" + lang_code
).exists()
# ensure that the default language is used in case no
# language is active at all
translation.deactivate_all()
assert self.TestModel.objects.filter(text="text_en").exists()
# ensure that hstore lookups still work
assert self.TestModel.objects.filter(text__ro="text_ro").exists()
def test_localized_lookup_specific_isnull(self):
self.TestModel.objects.create(
text=LocalizedValue(dict(en="text_en", ro="text_ro", nl=None))
)
translation.activate("nl")
assert (
self.TestModel.objects.annotate(text_localized=LocalizedRef("text"))
.filter(text_localized__isnull=True)
.exists()
)
class LocalizedRefLookupsTestCase(TestCase):
"""Tests whether ref lookups properly work with."""
TestModel1 = None
@classmethod
def setUpClass(cls):
"""Creates the test model in the database."""
super(LocalizedRefLookupsTestCase, cls).setUpClass()
cls.TestModel = get_fake_model({"text": LocalizedField()})
cls.TestModel.objects.create(
text=LocalizedValue(dict(en="text_en", ro="text_ro", nl="text_nl"))
)
def test_active_ref_lookup(self):
"""Tests whether active_ref lookup properly works."""
# assert that it properly lookups the currently active language
for lang_code, _ in settings.LANGUAGES:
translation.activate(lang_code)
assert self.TestModel.objects.filter(
text__active_ref=f"text_{lang_code}"
).exists()
# ensure that the default language is used in case no
# language is active at all
translation.deactivate_all()
assert self.TestModel.objects.filter(
text__active_ref="text_en"
).exists()
def test_translated_ref_lookup(self):
"""Tests whether translated_ref lookup properly works."""
# assert that it properly lookups the currently active language
for lang_code, _ in settings.LANGUAGES:
translation.activate(lang_code)
assert self.TestModel.objects.filter(
text__translated_ref=f"text_{lang_code}"
).exists()
# ensure that the default language is used in case no
# language is active at all
translation.deactivate_all()
assert self.TestModel.objects.filter(
text__translated_ref="text_en"
).exists()
fallbacks = {"cs": ["ru", "ro"], "pl": ["nl", "ro"]}
with override_settings(LOCALIZED_FIELDS_FALLBACKS=fallbacks):
with translation.override("cs"):
assert self.TestModel.objects.filter(
text__translated_ref="text_ro"
).exists()
with translation.override("pl"):
assert self.TestModel.objects.filter(
text__translated_ref="text_nl"
).exists()
# ensure that the default language is used in case no fallback is set
with translation.override("ru"):
assert self.TestModel.objects.filter(
text__translated_ref="text_en"
).exists()