mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-04-24 19:32:53 +03:00
Merge pull request #54 from sliverc/query_by_active_lang
Add support for localized query lookups
This commit is contained in:
commit
abd1587ca0
@ -345,6 +345,7 @@ Experimental feature
|
|||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
Enables the following experimental features:
|
Enables the following experimental features:
|
||||||
* ``LocalizedField`` will return ``None`` instead of an empty ``LocalizedValue`` if there is no database value.
|
* ``LocalizedField`` will return ``None`` instead of an empty ``LocalizedValue`` if there is no database value.
|
||||||
|
* ``LocalizedField`` lookups will lookup by currently active language instead of HStoreField
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'localized_fields.apps.LocalizedFieldsConfig'
|
@ -1,5 +1,21 @@
|
|||||||
|
import inspect
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from . import lookups
|
||||||
|
from .fields import LocalizedField
|
||||||
|
from .lookups import LocalizedLookupMixin
|
||||||
|
|
||||||
|
|
||||||
class LocalizedFieldsConfig(AppConfig):
|
class LocalizedFieldsConfig(AppConfig):
|
||||||
name = 'localized_fields'
|
name = 'localized_fields'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
if getattr(settings, 'LOCALIZED_FIELDS_EXPERIMENTAL', False):
|
||||||
|
for _, clazz in inspect.getmembers(lookups):
|
||||||
|
if not inspect.isclass(clazz) or clazz is LocalizedLookupMixin:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if issubclass(clazz, LocalizedLookupMixin):
|
||||||
|
LocalizedField.register_lookup(clazz)
|
||||||
|
80
localized_fields/lookups.py
Normal file
80
localized_fields/lookups.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.postgres.fields.hstore import KeyTransform
|
||||||
|
from django.contrib.postgres.lookups import (SearchLookup, TrigramSimilar,
|
||||||
|
Unaccent)
|
||||||
|
from django.db.models.expressions import Col
|
||||||
|
from django.db.models.lookups import (Contains, EndsWith, Exact, IContains,
|
||||||
|
IEndsWith, IExact, In, IRegex, IsNull,
|
||||||
|
IStartsWith, Regex, StartsWith)
|
||||||
|
from django.utils import translation
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
return super().process_lhs(qn, connection)
|
||||||
|
|
||||||
|
def get_prep_lookup(self):
|
||||||
|
return str(self.rhs)
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedSearchLookup(LocalizedLookupMixin, SearchLookup):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedUnaccent(LocalizedLookupMixin, Unaccent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedTrigramSimilair(LocalizedLookupMixin, TrigramSimilar):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedExact(LocalizedLookupMixin, Exact):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIExact(LocalizedLookupMixin, IExact):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIn(LocalizedLookupMixin, In):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedContains(LocalizedLookupMixin, Contains):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIContains(LocalizedLookupMixin, IContains):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedStartsWith(LocalizedLookupMixin, StartsWith):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIStartsWith(LocalizedLookupMixin, IStartsWith):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedEndsWith(LocalizedLookupMixin, EndsWith):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIEndsWith(LocalizedLookupMixin, IEndsWith):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIsNullWith(LocalizedLookupMixin, IsNull):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedRegexWith(LocalizedLookupMixin, Regex):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocalizedIRegexWith(LocalizedLookupMixin, IRegex):
|
||||||
|
pass
|
51
tests/test_lookups.py
Normal file
51
tests/test_lookups.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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.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()
|
Loading…
x
Reference in New Issue
Block a user