Dynamic global and instance settings for your django project
—
Django forms and views for web-based preference editing with dynamic form generation and validation. This provides comprehensive web interface components for managing preferences through standard Django forms and views.
Forms for editing individual preferences with automatic field generation based on preference type.
class AbstractSinglePreferenceForm(forms.ModelForm):
"""
Base form for editing single preferences.
Automatically generates appropriate form field based on
preference type and handles validation and saving.
"""
def __init__(self, *args, **kwargs):
"""
Initialize form with preference-specific field.
Args:
- *args: Standard form args
- **kwargs: Standard form kwargs plus preference info
"""
def clean(self):
"""
Validate preference exists in registry and value is valid.
Returns:
Cleaned form data
Raises:
- ValidationError: If preference not found or value invalid
"""
def save(self, commit=True):
"""
Save preference value through preference system.
Args:
- commit: Whether to save to database immediately
Returns:
Preference model instance
"""
class SinglePerInstancePreferenceForm(AbstractSinglePreferenceForm):
"""
Form for editing single per-instance preferences.
Handles preferences tied to specific model instances,
such as user-specific preferences.
"""
class Meta:
model = None # Set by subclasses
fields = '__all__'
class GlobalSinglePreferenceForm(AbstractSinglePreferenceForm):
"""
Form for editing single global preferences.
Specialized for global (site-wide) preferences with
appropriate model and field configuration.
"""
class Meta:
model = GlobalPreferenceModel
fields = '__all__'Forms for editing multiple preferences simultaneously with section organization and bulk updates.
class PreferenceForm(forms.Form):
"""
Base form for editing multiple preferences.
Dynamically generates fields for multiple preferences
and handles bulk updates through preference managers.
Attributes:
- registry: Associated preference registry
"""
registry = None
def __init__(self, *args, **kwargs):
"""
Initialize form with preference fields.
Args:
- *args: Standard form args
- **kwargs: Standard form kwargs plus preferences/section info
"""
def update_preferences(self, **kwargs):
"""
Update multiple preferences from form data.
Args:
- **kwargs: Additional options for preference manager
Returns:
Dictionary of updated preferences
"""
class GlobalPreferenceForm(PreferenceForm):
"""
Form for editing multiple global preferences.
Provides interface for bulk editing of global preferences
with proper validation and section organization.
"""
registry = global_preferences_registryFactory functions for creating dynamic preference forms based on registry configuration and filtering options.
def preference_form_builder(form_base_class, preferences=None, **kwargs):
"""
Build dynamic forms for preferences.
Creates form classes dynamically based on registry configuration
and filtering criteria. Supports section filtering, instance binding,
and custom field configuration.
Args:
- form_base_class: Base form class with registry attribute
- preferences (list): Specific preferences to include (optional)
- **kwargs: Additional options:
- section (str): Filter by section
- instance: Instance for per-instance preferences
- exclude (list): Preferences to exclude
- field_kwargs (dict): Custom field arguments
Returns:
Dynamically created form class
"""
def global_preference_form_builder(preferences=None, **kwargs):
"""
Shortcut for building global preference forms.
Args:
- preferences (list): Specific preferences to include (optional)
- **kwargs: Additional options (section, exclude, etc.)
Returns:
Dynamic GlobalPreferenceForm class
"""Django views for displaying and editing preferences with proper permissions and form handling.
class RegularTemplateView(TemplateView):
"""
Simple template view for testing preference context.
Template: "dynamic_preferences/testcontext.html"
"""
template_name = "dynamic_preferences/testcontext.html"
class PreferenceFormView(FormView):
"""
Display form for updating preferences by section.
Provides complete view for preference editing with
section filtering, form generation, and success handling.
Attributes:
- registry: Registry for preference lookups
- form_class: Form class for preference updates
- template_name: "dynamic_preferences/form.html"
"""
registry = None
form_class = None
template_name = "dynamic_preferences/form.html"
success_url = None
def dispatch(self, request, *args, **kwargs):
"""
Setup section from URL arguments.
Args:
- request: HTTP request
- *args: URL positional arguments
- **kwargs: URL keyword arguments (including section)
Returns:
HTTP response
"""
def get_form_class(self):
"""
Build dynamic form class based on section and registry.
Returns:
Form class configured for current section/preferences
"""
def get_context_data(self, **kwargs):
"""
Add registry and section information to template context.
Args:
- **kwargs: Base context data
Returns:
Updated context dictionary
"""
def form_valid(self, form):
"""
Update preferences on successful form submission.
Args:
- form: Valid form instance
Returns:
HTTP response (redirect to success URL)
"""from dynamic_preferences.views import PreferenceFormView
from dynamic_preferences.registries import global_preferences_registry
class GlobalPreferenceView(PreferenceFormView):
"""View for editing global preferences."""
registry = global_preferences_registry
template_name = 'admin/preferences/global_form.html'
success_url = '/preferences/global/'
def dispatch(self, request, *args, **kwargs):
# Check permissions
if not request.user.is_staff:
return HttpResponseForbidden()
return super().dispatch(request, *args, **kwargs)
# URL configuration
urlpatterns = [
path('preferences/global/', GlobalPreferenceView.as_view(), name='global_preferences'),
path('preferences/global/<str:section>/', GlobalPreferenceView.as_view(), name='global_preferences_section'),
]from dynamic_preferences.forms import global_preference_form_builder
from django.core.exceptions import ValidationError
def custom_preference_view(request):
"""Custom view with custom form validation."""
# Build form for specific section
PreferenceForm = global_preference_form_builder(section='general')
if request.method == 'POST':
form = PreferenceForm(request.POST)
if form.is_valid():
# Custom validation
if form.cleaned_data.get('general__maintenance_mode') and not request.user.is_superuser:
form.add_error(None, 'Only superusers can enable maintenance mode')
else:
form.update_preferences()
messages.success(request, 'Preferences updated successfully!')
return redirect('preferences')
else:
form = PreferenceForm()
return render(request, 'preferences_form.html', {'form': form})
# Advanced form with custom field configuration
def advanced_preference_view(request):
"""View with custom field configuration."""
PreferenceForm = global_preference_form_builder(
preferences=['general__title', 'general__description'],
field_kwargs={
'general__title': {
'widget': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter site title'})
},
'general__description': {
'widget': forms.Textarea(attrs={'class': 'form-control', 'rows': 4})
}
}
)
if request.method == 'POST':
form = PreferenceForm(request.POST)
if form.is_valid():
form.update_preferences()
return JsonResponse({'success': True})
else:
return JsonResponse({'success': False, 'errors': form.errors})
else:
form = PreferenceForm()
return render(request, 'advanced_preferences.html', {'form': form})class SectionPreferenceView(PreferenceFormView):
"""View for editing preferences by section."""
registry = global_preferences_registry
template_name = 'preferences/section_form.html'
def get_success_url(self):
section = self.kwargs.get('section')
return reverse('section_preferences', kwargs={'section': section})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
section = self.kwargs.get('section')
# Add section information
context['section'] = section
context['section_preferences'] = self.registry.preferences(section=section)
# Add navigation for other sections
context['all_sections'] = self.registry.sections()
return context
# Multiple section views
class PreferencesIndexView(TemplateView):
"""Index view showing all preference sections."""
template_name = 'preferences/index.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sections'] = global_preferences_registry.sections()
return context
# URL patterns
urlpatterns = [
path('preferences/', PreferencesIndexView.as_view(), name='preferences_index'),
path('preferences/<str:section>/', SectionPreferenceView.as_view(), name='section_preferences'),
]from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
import json
@method_decorator(csrf_exempt, name='dispatch')
class AjaxPreferenceUpdateView(View):
"""AJAX view for updating individual preferences."""
def post(self, request):
try:
data = json.loads(request.body)
preference_key = data.get('preference')
value = data.get('value')
if not preference_key or value is None:
return JsonResponse({'error': 'Missing preference or value'}, status=400)
# Update preference
global_preferences = global_preferences_registry.manager()
global_preferences[preference_key] = value
return JsonResponse({
'success': True,
'preference': preference_key,
'value': value,
'message': 'Preference updated successfully'
})
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
# JavaScript for AJAX updates
"""
async function updatePreference(key, value) {
const response = await fetch('/preferences/ajax-update/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify({
preference: key,
value: value
})
});
const result = await response.json();
if (result.success) {
showMessage('Preference updated!', 'success');
} else {
showMessage('Error: ' + result.error, 'error');
}
}
// Update preference on change
document.addEventListener('change', function(e) {
if (e.target.classList.contains('preference-field')) {
const key = e.target.dataset.preference;
const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
updatePreference(key, value);
}
});
"""from django import forms
from dynamic_preferences.forms import global_preference_form_builder
def custom_widget_view(request):
"""View with custom widgets for different preference types."""
# Custom widget configuration
widget_config = {
'ui__theme': forms.Select(attrs={'class': 'form-select'}),
'ui__primary_color': forms.TextInput(attrs={'type': 'color', 'class': 'form-control'}),
'general__description': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
'general__logo': forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}),
}
PreferenceForm = global_preference_form_builder(
section='ui',
field_kwargs={
key: {'widget': widget} for key, widget in widget_config.items()
}
)
if request.method == 'POST':
form = PreferenceForm(request.POST, request.FILES)
if form.is_valid():
form.update_preferences()
return redirect('ui_preferences')
else:
form = PreferenceForm()
return render(request, 'ui_preferences.html', {'form': form})
# Custom form class with additional methods
class ExtendedPreferenceForm(forms.Form):
"""Extended preference form with additional functionality."""
registry = global_preferences_registry
def __init__(self, *args, **kwargs):
self.section = kwargs.pop('section', None)
super().__init__(*args, **kwargs)
self.setup_preference_fields()
def setup_preference_fields(self):
"""Setup fields based on preferences."""
preferences = self.registry.preferences(section=self.section)
for pref in preferences:
field = pref.setup_field()
self.fields[pref.identifier()] = field
def clean(self):
"""Custom validation across preferences."""
cleaned_data = super().clean()
# Example: Validate theme and color compatibility
theme = cleaned_data.get('ui__theme')
primary_color = cleaned_data.get('ui__primary_color')
if theme == 'dark' and primary_color and primary_color.startswith('#F'):
self.add_error('ui__primary_color', 'Light colors not recommended for dark theme')
return cleaned_data
def save(self):
"""Save all preferences."""
manager = self.registry.manager()
for key, value in self.cleaned_data.items():
manager[key] = value
return manager<!-- preferences/section_form.html -->
<form method="post">
{% csrf_token %}
<h2>{{ section|title }} Preferences</h2>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% if field.errors %}
<div class="text-danger">
{% for error in field.errors %}
<small>{{ error }}</small>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Save Preferences</button>
</form>
<!-- Section navigation -->
<nav class="mt-4">
<h4>Other Sections</h4>
<ul class="list-unstyled">
{% for section in all_sections %}
<li><a href="{% url 'section_preferences' section.name %}">{{ section.verbose_name|default:section.name }}</a></li>
{% endfor %}
</ul>
</nav>Install with Tessl CLI
npx tessl i tessl/pypi-django-dynamic-preferences