mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-10-29 18:18:57 +03:00
no need inheritance from LocalizedModel anymore. Introduction of LocalizedValueDescriptor
This commit is contained in:
@@ -3,7 +3,6 @@ from .forms import LocalizedFieldForm, LocalizedFieldWidget
|
||||
from .fields import (LocalizedField, LocalizedBleachField,
|
||||
LocalizedAutoSlugField, LocalizedUniqueSlugField)
|
||||
from .mixins import AtomicSlugRetryMixin
|
||||
from .models import LocalizedModel
|
||||
from .localized_value import LocalizedValue
|
||||
|
||||
__all__ = [
|
||||
@@ -15,6 +14,5 @@ __all__ = [
|
||||
'LocalizedBleachField',
|
||||
'LocalizedFieldWidget',
|
||||
'LocalizedFieldForm',
|
||||
'LocalizedModel',
|
||||
'AtomicSlugRetryMixin'
|
||||
]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.conf import settings
|
||||
from django.db.utils import IntegrityError
|
||||
from django.utils import six, translation
|
||||
|
||||
from localized_fields import LocalizedFieldForm
|
||||
from psqlextra.fields import HStoreField
|
||||
@@ -7,6 +8,63 @@ from psqlextra.fields import HStoreField
|
||||
from ..localized_value import LocalizedValue
|
||||
|
||||
|
||||
class LocalizedValueDescriptor(object):
|
||||
"""
|
||||
The descriptor for the localized value attribute on the model instance.
|
||||
Returns a :see:LocalizedValue when accessed so you can do stuff like::
|
||||
|
||||
>>> from myapp.models import MyModel
|
||||
>>> instance = MyModel()
|
||||
>>> instance.value.en = 'English value'
|
||||
|
||||
Assigns a strings to active language key in :see:LocalizedValue on
|
||||
assignment so you can do::
|
||||
|
||||
>>> from django.utils import translation
|
||||
>>> from myapp.models import MyModel
|
||||
|
||||
>>> translation.activate('nl')
|
||||
>>> instance = MyModel()
|
||||
>>> instance.title = 'dutch title'
|
||||
>>> print(instance.title.nl) # prints 'dutch title'
|
||||
"""
|
||||
def __init__(self, field):
|
||||
self.field = field
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
if instance is None:
|
||||
return self
|
||||
|
||||
# This is slightly complicated, so worth an explanation.
|
||||
# `instance.localizedvalue` needs to ultimately return some instance of
|
||||
# `LocalizedValue`, probably a subclass.
|
||||
|
||||
# The instance dict contains whatever was originally assigned
|
||||
# in __set__.
|
||||
if self.field.name in instance.__dict__:
|
||||
value = instance.__dict__[self.field.name]
|
||||
else:
|
||||
instance.refresh_from_db(fields=[self.field.name])
|
||||
value = getattr(instance, self.field.name)
|
||||
|
||||
if value is None:
|
||||
attr = self.field.attr_class()
|
||||
instance.__dict__[self.field.name] = attr
|
||||
|
||||
if isinstance(value, dict):
|
||||
attr = self.field.attr_class(value)
|
||||
instance.__dict__[self.field.name] = attr
|
||||
|
||||
return instance.__dict__[self.field.name]
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if isinstance(value, six.string_types):
|
||||
self.__get__(instance).set(translation.get_language() or
|
||||
settings.LANGUAGE_CODE, value)
|
||||
else:
|
||||
instance.__dict__[self.field.name] = value
|
||||
|
||||
|
||||
class LocalizedField(HStoreField):
|
||||
"""A field that has the same value in multiple languages.
|
||||
|
||||
@@ -15,13 +73,23 @@ class LocalizedField(HStoreField):
|
||||
|
||||
Meta = None
|
||||
|
||||
# The class to wrap instance attributes in. Accessing to field attribute in
|
||||
# model instance will always return an instance of attr_class.
|
||||
attr_class = LocalizedValue
|
||||
|
||||
# The descriptor to use for accessing the attribute off of the class.
|
||||
descriptor_class = LocalizedValueDescriptor
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initializes a new instance of :see:LocalizedField."""
|
||||
|
||||
super(LocalizedField, self).__init__(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def from_db_value(value, *_):
|
||||
def contribute_to_class(self, cls, name, **kwargs):
|
||||
super(LocalizedField, self).contribute_to_class(cls, name, **kwargs)
|
||||
setattr(cls, self.name, self.descriptor_class(self))
|
||||
|
||||
def from_db_value(self, value, *_):
|
||||
"""Turns the specified database value into its Python
|
||||
equivalent.
|
||||
|
||||
@@ -36,9 +104,9 @@ class LocalizedField(HStoreField):
|
||||
"""
|
||||
|
||||
if not value:
|
||||
return LocalizedValue()
|
||||
return self.attr_class()
|
||||
|
||||
return LocalizedValue(value)
|
||||
return self.attr_class(value)
|
||||
|
||||
def to_python(self, value: dict) -> LocalizedValue:
|
||||
"""Turns the specified database value into its Python
|
||||
@@ -55,9 +123,9 @@ class LocalizedField(HStoreField):
|
||||
"""
|
||||
|
||||
if not value or not isinstance(value, dict):
|
||||
return LocalizedValue()
|
||||
return self.attr_class()
|
||||
|
||||
return LocalizedValue(value)
|
||||
return self.attr_class(value)
|
||||
|
||||
def get_prep_value(self, value: LocalizedValue) -> dict:
|
||||
"""Turns the specified value into something the database
|
||||
|
||||
@@ -1,34 +1 @@
|
||||
from psqlextra.models import PostgresModel
|
||||
|
||||
from .fields import LocalizedField
|
||||
from .localized_value import LocalizedValue
|
||||
|
||||
|
||||
class LocalizedModel(PostgresModel):
|
||||
"""A model that contains localized fields."""
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initializes a new instance of :see:LocalizedModel.
|
||||
|
||||
Here we set all the fields that are of :see:LocalizedField
|
||||
to an instance of :see:LocalizedValue in case they are none
|
||||
so that the user doesn't explicitely have to do so."""
|
||||
|
||||
super(LocalizedModel, self).__init__(*args, **kwargs)
|
||||
|
||||
for field in self._meta.get_fields():
|
||||
if not isinstance(field, LocalizedField):
|
||||
continue
|
||||
|
||||
value = getattr(self, field.name, None)
|
||||
|
||||
if not isinstance(value, LocalizedValue):
|
||||
if isinstance(value, dict):
|
||||
value = LocalizedValue(value)
|
||||
else:
|
||||
value = LocalizedValue()
|
||||
|
||||
setattr(self, field.name, value)
|
||||
|
||||
Reference in New Issue
Block a user