from six import string_types from django import forms from django.core.exceptions import ValidationError from collections import OrderedDict from .registries import global_preferences_registry from .models import GlobalPreferenceModel from .exceptions import NotFoundInRegistry class AbstractSinglePreferenceForm(forms.ModelForm): class Meta: fields = ("section", "name", "raw_value") def __init__(self, *args, **kwargs): self.instance = kwargs.get("instance") initial = {} if self.instance: initial["raw_value"] = self.instance.value kwargs["initial"] = initial super(AbstractSinglePreferenceForm, self).__init__(*args, **kwargs) if self.instance.name: self.fields["raw_value"] = self.instance.preference.setup_field() def clean(self): cleaned_data = super(AbstractSinglePreferenceForm, self).clean() try: self.instance.name, self.instance.section = ( cleaned_data["name"], cleaned_data["section"], ) except KeyError: # changelist form pass try: self.instance.preference except NotFoundInRegistry: raise ValidationError(NotFoundInRegistry.detail_default) return self.cleaned_data def save(self, *args, **kwargs): self.instance.value = self.cleaned_data["raw_value"] return super(AbstractSinglePreferenceForm, self).save(*args, **kwargs) class SinglePerInstancePreferenceForm(AbstractSinglePreferenceForm): class Meta: fields = ("instance",) + AbstractSinglePreferenceForm.Meta.fields def clean(self): cleaned_data = super(AbstractSinglePreferenceForm, self).clean() try: self.instance.name, self.instance.section = ( cleaned_data["name"], cleaned_data["section"], ) except KeyError: # changelist form pass i = cleaned_data.get("instance") if i: self.instance.instance = i try: self.instance.preference except NotFoundInRegistry: raise ValidationError(NotFoundInRegistry.detail_default) return self.cleaned_data class GlobalSinglePreferenceForm(AbstractSinglePreferenceForm): class Meta: model = GlobalPreferenceModel fields = AbstractSinglePreferenceForm.Meta.fields def preference_form_builder(form_base_class, preferences=[], **kwargs): """ Return a form class for updating preferences :param form_base_class: a Form class used as the base. Must have a ``registry` attribute :param preferences: a list of :py:class: :param section: a section where the form builder will load preferences """ registry = form_base_class.registry preferences_obj = [] if len(preferences) > 0: # Preferences have been selected explicitly for pref in preferences: if isinstance(pref, string_types): preferences_obj.append(registry.get(name=pref)) elif type(pref) == tuple: preferences_obj.append(registry.get(name=pref[0], section=pref[1])) else: raise NotImplementedError( "The data you provide can't be converted to a Preference object" ) elif kwargs.get("section", None): # Try to use section param preferences_obj = registry.preferences(section=kwargs.get("section", None)) else: # display all preferences in the form preferences_obj = registry.preferences() fields = OrderedDict() instances = [] if "model" in kwargs: # backward compat, see #212 manager_kwargs = kwargs.get("model") else: manager_kwargs = {"instance": kwargs.get("instance", None)} manager = registry.manager(**manager_kwargs) for preference in preferences_obj: f = preference.field instance = manager.get_db_pref( section=preference.section.name, name=preference.name ) f.initial = instance.value fields[preference.identifier()] = f instances.append(instance) form_class = type("Custom" + form_base_class.__name__, (form_base_class,), {}) form_class.base_fields = fields form_class.preferences = preferences_obj form_class.instances = instances form_class.manager = manager return form_class def global_preference_form_builder(preferences=[], **kwargs): """ A shortcut :py:func:`preference_form_builder(GlobalPreferenceForm, preferences, **kwargs)` """ return preference_form_builder(GlobalPreferenceForm, preferences, **kwargs) class PreferenceForm(forms.Form): registry = None def update_preferences(self, **kwargs): for instance in self.instances: self.manager.update_db_pref( instance.preference.section.name, instance.preference.name, self.cleaned_data[instance.preference.identifier()], ) class GlobalPreferenceForm(PreferenceForm): registry = global_preferences_registry