import logging from django import forms from django.apps import apps from django.core.exceptions import ImproperlyConfigured from .. import converters logger = logging.getLogger(__name__) app_config = apps.get_containing_app_config(__package__) class ChainedForm(forms.Form): _form_title = None _initial_form_name = None _next_form_name = None def __init__(self, *args, **kwargs): self._session_data = dict() self._request = kwargs.pop('request', None) self._load_session_data() if 'initial' not in kwargs: kwargs['initial'] = self._session_data else: kwargs['initial'].update(self._session_data) super(ChainedForm, self).__init__(*args, **kwargs) self._proceed_session_data(self._session_data) def _serialize_value(self, value): return converters.Iso8601Serializer.serialize(value, ignore_unsupported_input=True) def _deserialize_value(self, value): return converters.Iso8601Serializer.deserialize(value, ignore_unsupported_input=True) def _load_session_data(self): if self._request is not None and hasattr(self._request, 'session'): session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) session_data = self._request.session.get(session_var_name, dict()) for k in session_data: self._session_data[k] = self._deserialize_value(session_data[k]) def _proceed_session_data(self, session_data): pass def _save_session_data(self): if self._request is not None and hasattr(self._request, 'session'): session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) session_data = dict() for k in self._session_data: session_data[k] = self._serialize_value(self._session_data[k]) self._request.session[session_var_name] = session_data def _post_clean(self): self._session_data.update(self.cleaned_data) self._save_session_data() @property def form_name(self): return self.__class__.__name__ @property def form_title(self): return self.__class__.get_form_title() @property def initial_form_name(self): return self.__class__.get_initial_form_name() @property def next_form_name(self): return self.__class__.get_next_form_name() @classmethod def get_form_name(cls): return cls.__name__ @classmethod def get_form_title(cls): if cls._form_title is not None: return cls._form_title n = cls.get_form_name() if n.endswith('Form'): n = n[:-len('Form')] return n @classmethod def get_initial_form_name(cls): return cls._initial_form_name or cls.__name__ @classmethod def get_next_form_name(cls): return cls._next_form_name def get_initial_for_field(self, field, field_name): value = super(ChainedForm, self).get_initial_for_field(field, field_name) if value is None: form_name = self.__class__.__name__ form_initials = app_config.settings.form_initials if form_name in form_initials and field_name in form_initials[form_name]: value = app_config.settings.form_initials[form_name][field_name].get_value(self._session_data) return value def flush_session_data(self): if self._request is not None and hasattr(self._request, 'session'): session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) if session_var_name in self._request.session: del self._request.session[session_var_name] self._session_data = dict() class ModelMixin(object): _model = None def _get_model(self): if not self._model: raise ImproperlyConfigured('{cls} is missing a Model.' ' Define {cls}._model'.format(cls=self.__class__.__name__)) return self._model def _get_instance_kwargs(self): return self.cleaned_data def get_instance(self): model = self._get_model() kwargs1 = self._get_instance_kwargs() kwargs2 = dict() for attr in kwargs1: if hasattr(model, attr): kwargs2[attr] = kwargs1[attr] return model(**kwargs2)