Settings for packages.
Project description
WebCase Settings
A flexible Django settings framework for defining, validating, and managing application-wide and per-user settings using Pydantic DTOs, Django ORM, and lazy resolvers.
Installation
pip install wc-django-settings
In settings.py:
INSTALLED_APPS += [
'wcd_settings',
]
MIDDLEWARE += [
'wcd_settings.middleware.settings_middleware',
]
Usage
1. Defining and Registering Settings
1.1 Define DTOs (Pydantic Models)
Create Pydantic models to define the shape and validation of your settings.
# myapp/dtos.py
from wcd_settings.registries import SettingsDTO
class ThemeSettings(SettingsDTO):
color_scheme: str = Field(default='light', description='Theme color scheme')
font_size: int = Field(default=14, ge=8, le=32, description='Font size in px')
class NotificationsSettings(SettingsDTO):
enabled: bool = Field(default=True, description='Enable notifications')
frequency: str = Field(default='daily', description='Notification frequency')
1.2 Register DTOs
Register these models with app_settings_registry (for global settings) or user_settings_registry (for per-user settings).
# myapp/registry.py
from wcd_settings.registries import (
AppSettingsDescriptor, UserSettingsDescriptor,
app_settings_registry, user_settings_registry,
)
from .dtos import ThemeSettings, NotificationsSettings
# Application-wide setting
app_settings_registry.register(
AppSettingsDescriptor(
# Unique key
key='theme',
# DTO model to validate settings
dto=ThemeSettings,
# Optional json schema object that describes DTO
schema=ThemeSettings.model_json_schema(),
# Defines whether this object could be edited through HTTP API
is_editable=False,
# Defines whether this object could be accessed through HTTP API
is_readable=True,
)
)
# User-specific setting
user_settings_registry.register(
UserSettingsDescriptor(
key='notifications', dto=NotificationsSettings,
schema=NotificationsSettings.model_json_schema(),
is_editable=True, is_readable=True,
)
)
2. Fetching Settings with Resolvers
Resolvers provide lazy-loading and caching of settings from the database.
from wcd_settings import shortcuts
# App Settings
# Optional request parameter to use middleware-injected settings and cahe
app_settings = shortcuts.app_settings(request=None)
theme: Optional[ThemeSettings] = app_settings.resolver.get('theme')
print(theme.color_scheme) # "light" by default or DB value
# User Settings
user_settings = shortcuts.user_settings(request=None)
# Getting settings for user_id=42
notifications: Optional[NotificationsSettings] = user_settings.resolver.get((42, 'notifications'))
if notifications.enabled:
print('User has notifications enabled')
Or without shortcuts:
from wcd_settings.resolvers import (
make_app_resolver, make_user_resolver,
)
from wcd_settings.setters import (
make_app_setter, make_user_setter,
)
app_resolver = make_app_resolver()
user_resolver = make_user_resolver()
# You may use resolvers separately:
theme: Optional[ThemeSettings] = app_resolver.get('theme')
notifications: Optional[NotificationsSettings] = user_resolver.get((42, 'notifications'))
# And them create setters based on them:
app_settings = make_app_setter(app_resolver)
user_settings = make_user_setter(user_resolver)
3. Updating Settings with Setters
Setters update settings in the database with full Pydantic validation.
3.1 Application Settings Setter
from wcd_settings import shortcuts
from myapp.dtos import ThemeSettings
app_settings = shortcuts.app_settings(request=None)
# Update theme settings
theme_dto = ThemeSettings(color_scheme='dark', font_size=16)
app_settings.save('theme', theme_dto)
3.2 User Settings Setter
from wcd_settings.setters import make_user_setter
from myapp.dtos import NotificationsSettings
user_settings = shortcuts.user_settings(request=None)
# Update user notifications settings
user_id = 42
notif_dto = NotificationsSettings(enabled=False, frequency='weekly')
user_settings.save((user_id, 'notifications'), notif_dto)
4 Access Settings in Views
Use the request.app_settings and request.user_settings properties injected by middleware.
# views.py
from django.http import JsonResponse
def profile_view(request):
theme = request.app_settings.resolver.get('theme')
notifications = request.user_settings.resolver.get((request.user.id, 'notifications'))
return JsonResponse({
'theme': theme.color_scheme,
'notifications_enabled': notifications.enabled,
})
5. Advanced Usage
5.1 Partial Updates
You can update nested fields within a settings DTO:
from wcd_settings.setters import AppSettingsSetAction
actions = [
AppSettingsSetAction(key='theme', path=['font_size'], value=18),
AppSettingsSetAction(key='theme', path=['color_scheme'], value='dark'),
]
setter = make_app_setter(make_app_resolver())
commit, failures = setter.set(actions)
if not failures:
commit() # Save changes
You may even inject values into more complex datastructures
from wcd_settings.setters import UserSettingsSetAction
from wcd_settings.registries import (
SettingsDTO, UserSettingsDescriptor,
user_settings_registry,
)
from wcd_settings.resolvers import make_user_resolver
from wcd_settings.setters import make_user_setter
class Nested(SettingsDTO):
value: List[Optional[str]] = Field(default_factory=list)
class Complex(SettingsDTO):
title: Optional[str] = None
nested: Nested = Field(default_factory=Nested)
# User-specific setting
user_settings_registry.register(
UserSettingsDescriptor(
key='complex', dto=Complex,
schema=Complex.model_json_schema(),
is_editable=True, is_readable=True,
)
)
actions = [
UserSettingsSetAction((1, 'complex'), path=['title'], value='Title'),
UserSettingsSetAction(
(1, 'complex'),
# Path could also inject values by list indexes:
path=['nested', 'value', 0],
value='first',
),
UserSettingsSetAction(
(1, 'complex'),
# Even if index is larger than current data length all the previous
# items in the list will be filled with `None`'s.
# Be aware, that DTO validation should also support that.
path=['nested', 'value', 3],
value='fourth',
),
]
setter = make_user_setter(make_user_resolver())
commit, failures = setter.set(actions)
if not failures:
commit() # Save changes
6. Views
# urls.py
from wcd_settings.urls import make_urlpatterns
# This will add views for getting and editing app and user settings:
urlpatterns += make_urlpatterns()
After that you may call:
/api/v1/settings/app/all/- Retrieving all the app settings./api/v1/settings/app/set/- Setting the values for the app settings./api/v1/settings/own/all/- Retrieving all the current user's settings./api/v1/settings/own/set/- Setting the values for the current user's settings.
From the example above calling the /api/v1/settings/own/set/ with:
{
"actions": [
{"path": ["complex", "title"], "value": "Title"},
{"path": ["complex", "nested", "value", 0], "value": "one"},
]
}
Will update the user's settings to the following:
settings = Complex(
title='Title',
nested=Nested(
value=['one'],
),
)
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.1.2]
Getters and setters are fully functional.
[0.1.0]
Initial version.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file wc_django_settings-0.1.2.tar.gz.
File metadata
- Download URL: wc_django_settings-0.1.2.tar.gz
- Upload date:
- Size: 36.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd5c9d87616ccd1dba8b7cc87225c99a834247d5d05a5343bc5cbcc56da44bf8
|
|
| MD5 |
7d2d6969146f3230fe5195399106ccba
|
|
| BLAKE2b-256 |
d3c4f47e30b1f884c57bc9190af2ae8c9d88ba7cbaf0db8d61043575b34fc95f
|