diff --git a/localized_fields/lookups.py b/localized_fields/lookups.py index ba38980..ea7faed 100644 --- a/localized_fields/lookups.py +++ b/localized_fields/lookups.py @@ -23,6 +23,7 @@ from django.db.models.lookups import ( StartsWith, ) from django.utils import translation +from psqlextra.expressions import HStoreColumn from .fields import LocalizedField @@ -37,14 +38,33 @@ except ImportError: class LocalizedLookupMixin: def process_lhs(self, qn, connection): - if isinstance(self.lhs, Col): - language = translation.get_language() or settings.LANGUAGE_CODE - self.lhs = KeyTransform(language, self.lhs) + # If the LHS is already a reference to a specific hstore key, there + # is nothing to be done since it already references as specific language. + if isinstance(self.lhs, HStoreColumn) or isinstance( + self.lhs, KeyTransform + ): + return super().process_lhs(qn, connection) + + # If this is something custom expression, we don't really know how to + # handle that, so we better do nothing. + if not isinstance(self.lhs, Col): + return super().process_lhs(qn, connection) + + # Select the key for the current language. We do this so that + # + # myfield__= + # + # Is converted into: + # + # myfield____= + language = translation.get_language() or settings.LANGUAGE_CODE + self.lhs = KeyTransform(language, self.lhs) + return super().process_lhs(qn, connection) def get_prep_lookup(self): - # Django 4.0 removed the ability for isnull fields to be something other than a bool - # We should NOT convert them to strings + # Django 4.0 removed the ability for isnull fields to be something + # other than a bool We should NOT convert them to strings if isinstance(self.rhs, bool): return self.rhs return str(self.rhs) diff --git a/tests/test_lookups.py b/tests/test_lookups.py index a2ff21f..1a83860 100644 --- a/tests/test_lookups.py +++ b/tests/test_lookups.py @@ -3,6 +3,7 @@ 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 @@ -49,6 +50,18 @@ class LocalizedLookupsTestCase(TestCase): # 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."""