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() def _get_model(self): if not hasattr(self, '_model'): raise ImproperlyConfigured('{cls} is missing a Model.' ' Define {cls}._model'.format(cls=self.__class__.__name__)) return self._model def _get_object(self, model_kwargs): return self._get_model()(**model_kwargs) @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): 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) else: value = super(ChainedForm, self).get_initial_for_field(field, field_name) return value def save(self): object_kwargs = dict() data = self._session_data.copy() if 'deadline' in data: buf = data['deadline'] if isinstance(buf, basestring): deadline_choice = buf.lower() deadline_field = 'deadline_{}'.format(deadline_choice) if deadline_field in data: data['deadline'] = data[deadline_field] model = self._get_model() for field in data: if hasattr(model, field): object_kwargs[field] = data[field] return self._get_object(object_kwargs) 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()