diff --git a/formwizard/views.py b/formwizard/views.py index 9af668b..1790372 100644 --- a/formwizard/views.py +++ b/formwizard/views.py @@ -83,9 +83,9 @@ def step1(self): return int(self.index) + 1 -class WizardView(TemplateView): +class WizardMixin(object): """ - The WizardView is used to create multi-page forms and handles all the + The WizardMixin is used to create multi-page forms and handles all the storage and validation stuff. The wizard is based on Django's generic class based views. """ @@ -94,81 +94,10 @@ class based views. initial_dict = None instance_dict = None condition_dict = None - template_name = 'formwizard/wizard_form.html' def __repr__(self): return '<%s: forms: %s>' % (self.__class__.__name__, self.form_list) - @classonlymethod - def as_view(cls, *args, **kwargs): - """ - This method is used within urls.py to create unique formwizard - instances for every request. We need to override this method because - we add some kwargs which are needed to make the formwizard usable. - """ - initkwargs = cls.get_initkwargs(*args, **kwargs) - return super(WizardView, cls).as_view(**initkwargs) - - @classmethod - def get_initkwargs(cls, form_list, initial_dict=None, - instance_dict=None, condition_dict=None, *args, **kwargs): - """ - Creates a dict with all needed parameters for the form wizard instances. - - * `form_list` - is a list of forms. The list entries can be single form - classes or tuples of (`step_name`, `form_class`). If you pass a list - of forms, the formwizard will convert the class list to - (`zero_based_counter`, `form_class`). This is needed to access the - form for a specific step. - * `initial_dict` - contains a dictionary of initial data dictionaries. - The key should be equal to the `step_name` in the `form_list` (or - the str of the zero based counter - if no step_names added in the - `form_list`) - * `instance_dict` - contains a dictionary of instance objects. This list - is only used when `ModelForm`s are used. The key should be equal to - the `step_name` in the `form_list`. Same rules as for `initial_dict` - apply. - * `condition_dict` - contains a dictionary of boolean values or - callables. If the value of for a specific `step_name` is callable it - will be called with the formwizard instance as the only argument. - If the return value is true, the step's form will be used. - """ - kwargs.update({ - 'initial_dict': initial_dict or {}, - 'instance_dict': instance_dict or {}, - 'condition_dict': condition_dict or {}, - }) - init_form_list = SortedDict() - - assert len(form_list) > 0, 'at least one form is needed' - - # walk through the passed form list - for i, form in enumerate(form_list): - if isinstance(form, (list, tuple)): - # if the element is a tuple, add the tuple to the new created - # sorted dictionary. - init_form_list[unicode(form[0])] = form[1] - else: - # if not, add the form with a zero based counter as unicode - init_form_list[unicode(i)] = form - - # walk through the ne created list of forms - for form in init_form_list.itervalues(): - if issubclass(form, formsets.BaseFormSet): - # if the element is based on BaseFormSet (FormSet/ModelFormSet) - # we need to override the form variable. - form = form.form - # check if any form contains a FileField, if yes, we need a - # file_storage added to the formwizard (by subclassing). - for field in form.base_fields.itervalues(): - if (isinstance(field, forms.FileField) and - not hasattr(cls, 'file_storage')): - raise NoFileStorageConfigured - - # build the kwargs for the formwizard instances - kwargs['form_list'] = init_form_list - return kwargs - def get_wizard_name(self): return normalize_name(self.__class__.__name__) @@ -215,7 +144,7 @@ def dispatch(self, request, *args, **kwargs): self.storage = get_storage(self.storage_name, self.prefix, request, getattr(self, 'file_storage', None)) self.steps = StepsHelper(self) - response = super(WizardView, self).dispatch(request, *args, **kwargs) + response = super(WizardMixin, self).dispatch(request, *args, **kwargs) # update the response (e.g. adding cookies) self.storage.update_response(response) @@ -519,7 +448,7 @@ def get_context_data(self, form, **kwargs): context.update({'another_var': True}) return context """ - context = super(WizardView, self).get_context_data(*args, **kwargs) + context = super(WizardMixin, self).get_context_data(*args, **kwargs) context.update(self.storage.extra_data) context['wizard'] = { 'form': form, @@ -547,6 +476,82 @@ def done(self, form_list, **kwargs): "method, which is required." % self.__class__.__name__) +class BaseWizardView(WizardMixin): + @classonlymethod + def as_view(cls, *args, **kwargs): + """ + This method is used within urls.py to create unique formwizard + instances for every request. We need to override this method because + we add some kwargs which are needed to make the formwizard usable. + """ + initkwargs = cls.get_initkwargs(*args, **kwargs) + return super(BaseWizardView, cls).as_view(**initkwargs) + + @classmethod + def get_initkwargs(cls, form_list, initial_dict=None, + instance_dict=None, condition_dict=None, *args, **kwargs): + """ + Creates a dict with all needed parameters for the form wizard instances. + + * `form_list` - is a list of forms. The list entries can be single form + classes or tuples of (`step_name`, `form_class`). If you pass a list + of forms, the formwizard will convert the class list to + (`zero_based_counter`, `form_class`). This is needed to access the + form for a specific step. + * `initial_dict` - contains a dictionary of initial data dictionaries. + The key should be equal to the `step_name` in the `form_list` (or + the str of the zero based counter - if no step_names added in the + `form_list`) + * `instance_dict` - contains a dictionary of instance objects. This list + is only used when `ModelForm`s are used. The key should be equal to + the `step_name` in the `form_list`. Same rules as for `initial_dict` + apply. + * `condition_dict` - contains a dictionary of boolean values or + callables. If the value of for a specific `step_name` is callable it + will be called with the formwizard instance as the only argument. + If the return value is true, the step's form will be used. + """ + kwargs.update({ + 'initial_dict': initial_dict or {}, + 'instance_dict': instance_dict or {}, + 'condition_dict': condition_dict or {}, + }) + init_form_list = SortedDict() + + assert len(form_list) > 0, 'at least one form is needed' + + # walk through the passed form list + for i, form in enumerate(form_list): + if isinstance(form, (list, tuple)): + # if the element is a tuple, add the tuple to the new created + # sorted dictionary. + init_form_list[unicode(form[0])] = form[1] + else: + # if not, add the form with a zero based counter as unicode + init_form_list[unicode(i)] = form + + # walk through the ne created list of forms + for form in init_form_list.itervalues(): + if issubclass(form, formsets.BaseFormSet): + # if the element is based on BaseFormSet (FormSet/ModelFormSet) + # we need to override the form variable. + form = form.form + # check if any form contains a FileField, if yes, we need a + # file_storage added to the formwizard (by subclassing). + for field in form.base_fields.itervalues(): + if (isinstance(field, forms.FileField) and + not hasattr(cls, 'file_storage')): + raise NoFileStorageConfigured + + # build the kwargs for the formwizard instances + kwargs['form_list'] = init_form_list + return kwargs + + +class WizardView(BaseWizardView, TemplateView): + template_name = 'formwizard/wizard_form.html' + + class SessionWizardView(WizardView): """ A WizardView with pre-configured SessionStorage backend.