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
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)
|