1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
"""
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)
|