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.
Metadata
Release files for wc-django-settings 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| wc_django_settings-0.1.2.tar.gz | 36.2 kB | Without provenance | Details |
Release files / wc_django_settings-0.1.2.tar.gz
| Download URL | wc_django_settings-0.1.2.tar.gz |
|---|---|
| Size | 36.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dd5c9d87616ccd1dba8b7cc87225c99a834247d5d05a5343bc5cbcc56da44bf8
|
|
BLAKE2b-256 checksum How to use checksums |
d3c4f47e30b1f884c57bc9190af2ae8c9d88ba7cbaf0db8d61043575b34fc95f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Security for wc-django-settings 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.