Skip to content
This repository has been archived by the owner on Dec 23, 2018. It is now read-only.

Split WizardView into WizardMixin, BaseWizardView and WizardView #34

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 80 additions & 75 deletions formwizard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -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__)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down