You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

135 lines
3.7 KiB

"""
Preference models, queryset and managers that handle the logic for persisting preferences.
"""
from django.db import models
from django.db.models.query import QuerySet
from django.conf import settings
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from dynamic_preferences.registries import (
preference_models,
global_preferences_registry,
)
from .utils import update
class BasePreferenceModel(models.Model):
"""
A base model with common logic for all preferences models.
"""
#: The section under which the preference is declared
section = models.CharField(
max_length=150,
db_index=True,
blank=True,
null=True,
default=None,
verbose_name=_("Section Name"),
)
#: a name for the preference
name = models.CharField(_("Name"), max_length=150, db_index=True)
#: a value, serialized to a string. This field should not be accessed directly, use :py:attr:`BasePreferenceModel.value` instead
raw_value = models.TextField(_("Raw Value"), null=True, blank=True)
class Meta:
abstract = True
app_label = "dynamic_preferences"
@cached_property
def preference(self):
return self.registry.get(section=self.section, name=self.name, fallback=True)
@property
def verbose_name(self):
return self.preference.get("verbose_name", self.preference.identifier)
verbose_name.fget.short_description = _("Verbose Name")
@property
def help_text(self):
return self.preference.get("help_text", "")
help_text.fget.short_description = _("Help Text")
def set_value(self, value):
"""
Save serialized self.value to self.raw_value
"""
self.raw_value = self.preference.serializer.serialize(value)
def get_value(self):
"""
Return deserialized self.raw_value
"""
return self.preference.serializer.deserialize(self.raw_value)
value = property(get_value, set_value)
def save(self, **kwargs):
if self.pk is None and not self.raw_value:
self.value = self.preference.get("default")
super(BasePreferenceModel, self).save(**kwargs)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "{0} - {1}/{2}".format(self.__class__.__name__, self.section, self.name)
class GlobalPreferenceModel(BasePreferenceModel):
registry = global_preferences_registry
class Meta:
unique_together = ("section", "name")
app_label = "dynamic_preferences"
verbose_name = _("Global preference")
verbose_name_plural = _("Global preferences")
class PerInstancePreferenceModel(BasePreferenceModel):
"""For preferences that are tied to a specific model instance"""
#: the instance which is concerned by the preference
#: use a ForeignKey pointing to the model of your choice
instance = None
class Meta(BasePreferenceModel.Meta):
unique_together = ("instance", "section", "name")
abstract = True
@classmethod
def get_instance_model(cls):
return cls._meta.get_field("instance").remote_field.model
global_preferences_registry.preference_model = GlobalPreferenceModel
# Create default preferences for new instances
from django.db.models.signals import post_save
def invalidate_cache(sender, created, instance, **kwargs):
if not isinstance(instance, BasePreferenceModel):
return
registry = preference_models.get_by_preference(instance)
linked_instance = getattr(instance, "instance", None)
kwargs = {}
if linked_instance:
kwargs["instance"] = linked_instance
manager = registry.manager(**kwargs)
manager.to_cache(instance)
post_save.connect(invalidate_cache)