Dynamic global and instance settings for your django project
npx @tessl/cli install tessl/pypi-django-dynamic-preferences@1.17.0A Django package that provides dynamic preferences/settings functionality, allowing configuration values to be stored in the database and managed through Django's admin interface or REST API. This enables runtime configuration changes without server restarts, supporting both global settings and per-user preferences.
pip install django-dynamic-preferencesfrom dynamic_preferences.registries import global_preferences_registry
from dynamic_preferences.types import BooleanPreference, StringPreference
from dynamic_preferences.preferences import SectionFor user-specific preferences:
from dynamic_preferences.users.registries import user_preferences_registry# settings.py
INSTALLED_APPS = [
# ...
'dynamic_preferences',
]
# Create a preferences registry file (e.g., dynamic_preferences_registry.py)
from dynamic_preferences.preferences import Section
from dynamic_preferences.registries import global_preferences_registry
from dynamic_preferences.types import BooleanPreference, StringPreference
# Define sections
general = Section('general')
ui = Section('ui')
# Register preferences
@global_preferences_registry.register
class SiteTitle(StringPreference):
section = general
name = 'title'
default = 'My Site'
verbose_name = 'Site title'
@global_preferences_registry.register
class MaintenanceMode(BooleanPreference):
section = general
name = 'maintenance_mode'
default = False
verbose_name = 'Maintenance mode'
# Usage in views/code
from dynamic_preferences.registries import global_preferences_registry
def my_view(request):
global_preferences = global_preferences_registry.manager()
site_title = global_preferences['general__title']
maintenance_mode = global_preferences['general__maintenance_mode']
# Update preferences
global_preferences['general__title'] = 'New Site Title'
return render(request, 'template.html', {
'site_title': site_title,
'maintenance_mode': maintenance_mode,
})Django Dynamic Preferences uses a layered architecture:
Database models for storing preferences and manager classes for cached preference access with automatic synchronization.
class BasePreferenceModel(models.Model):
section = models.CharField(max_length=150)
name = models.CharField(max_length=150)
raw_value = models.TextField()
@property
def value(self): ...
@value.setter
def value(self, value): ...
class GlobalPreferenceModel(BasePreferenceModel): ...
class PreferencesManager:
def __getitem__(self, key: str): ...
def __setitem__(self, key: str, value): ...
def get(self, key: str, no_cache: bool = False): ...
def all(self) -> dict: ...Built-in preference types with automatic serialization, form field generation, and validation for various data types.
class BasePreferenceType:
field_class = None
serializer = None
default = None
def validate(self, value): ...
def api_repr(self, value): ...
class BooleanPreference(BasePreferenceType): ...
class StringPreference(BasePreferenceType): ...
class IntegerPreference(BasePreferenceType): ...
class ChoicePreference(BasePreferenceType):
choices = ()
class ModelChoicePreference(BasePreferenceType):
model = None
queryset = NoneRegistration and organization system for preferences with section support and manager instantiation.
class PreferenceRegistry:
name: str
preference_model = None
def register(self, preference_class): ...
def get(self, name: str, section: str = None): ...
def manager(self, **kwargs) -> PreferencesManager: ...
def sections(self) -> list: ...
class GlobalPreferenceRegistry(PreferenceRegistry): ...
global_preferences_registry: GlobalPreferenceRegistryComplete Django admin interface integration with custom admin classes, forms, and filters for preference management.
class DynamicPreferenceAdmin(admin.ModelAdmin):
list_display = ('verbose_name', 'name', 'section_name', 'help_text', 'raw_value', 'default_value')
readonly_fields = ('name', 'section_name', 'default_value')
search_fields = ('name', 'section', 'raw_value')
class GlobalPreferenceAdmin(DynamicPreferenceAdmin): ...Django REST Framework integration providing serializers, viewsets, and permissions for API-based preference management.
class PreferenceSerializer(serializers.Serializer):
section = serializers.CharField(read_only=True)
name = serializers.CharField(read_only=True)
value = PreferenceValueField()
verbose_name = serializers.SerializerMethodField()
class GlobalPreferencesViewSet(viewsets.GenericViewSet):
def list(self, request): ...
def retrieve(self, request, pk=None): ...
def update(self, request, pk=None): ...
def bulk(self, request): ...User-specific preferences system with models, forms, admin integration, and API support for per-user settings.
class UserPreferenceModel(PerInstancePreferenceModel):
instance = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class UserPreferenceRegistry(PerInstancePreferenceRegistry): ...
user_preferences_registry: UserPreferenceRegistry
class UserPreferencesViewSet(PerInstancePreferenceViewSet): ...Django forms and views for web-based preference editing with dynamic form generation and validation.
class AbstractSinglePreferenceForm(forms.ModelForm):
def __init__(self, *args, **kwargs): ...
def save(self, commit=True): ...
class PreferenceForm(forms.Form):
registry = None
def update_preferences(self, **kwargs): ...
def preference_form_builder(form_base_class, preferences=None, **options): ...
def global_preference_form_builder(preferences=None, **options): ...
class PreferenceFormView(FormView):
registry = None
def get_form_class(self): ...Value serialization system for database storage with support for complex Python objects and custom serialization logic.
class BaseSerializer:
@classmethod
def serialize(cls, value, **kwargs) -> str: ...
@classmethod
def deserialize(cls, value, **kwargs): ...
class BooleanSerializer(BaseSerializer): ...
class StringSerializer(BaseSerializer): ...
class ModelSerializer(InstanciatedSerializer): ...
class FileSerializer(InstanciatedSerializer): ...Django signal system integration for reacting to preference changes with custom logic, logging, or cache invalidation.
from django.dispatch import Signal
preference_updated: SignalDjango framework integration features including template context processors for automatic preference injection into template context.
def global_preferences(request):
"""Template context processor for global preferences."""
...class Section:
def __init__(self, name: str, verbose_name: str = None): ...
name: str
verbose_name: str
class AbstractPreference:
section: Section
name: str
default: Any
verbose_name: str
help_text: str
def identifier(self) -> str: ...
# Constants
EMPTY_SECTION: Section
UNSET: UnsetValue
# Exceptions
class DynamicPreferencesException(Exception): ...
class NotFoundInRegistry(DynamicPreferencesException, KeyError): ...
class MissingDefault(DynamicPreferencesException): ...