summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py')
-rw-r--r--lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py730
1 files changed, 730 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py b/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
new file mode 100644
index 0000000..494d87a
--- /dev/null
+++ b/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
@@ -0,0 +1,730 @@
+import re
+
+from django import forms
+from django.shortcuts import redirect
+from django.core.urlresolvers import reverse
+from django.forms import formsets, ValidationError
+from django.views.generic import TemplateView
+from django.utils.datastructures import SortedDict
+from django.utils.decorators import classonlymethod
+from django.utils.translation import ugettext as _
+from django.utils import six
+
+from django.contrib.formtools.wizard.storage import get_storage
+from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
+from django.contrib.formtools.wizard.forms import ManagementForm
+
+
+def normalize_name(name):
+ """
+ Converts camel-case style names into underscore seperated words. Example::
+
+ >>> normalize_name('oneTwoThree')
+ 'one_two_three'
+ >>> normalize_name('FourFiveSix')
+ 'four_five_six'
+
+ """
+ new = re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', name)
+ return new.lower().strip('_')
+
+class StepsHelper(object):
+
+ def __init__(self, wizard):
+ self._wizard = wizard
+
+ def __dir__(self):
+ return self.all
+
+ def __len__(self):
+ return self.count
+
+ def __repr__(self):
+ return '<StepsHelper for %s (steps: %s)>' % (self._wizard, self.all)
+
+ @property
+ def all(self):
+ "Returns the names of all steps/forms."
+ return list(self._wizard.get_form_list())
+
+ @property
+ def count(self):
+ "Returns the total number of steps/forms in this the wizard."
+ return len(self.all)
+
+ @property
+ def current(self):
+ """
+ Returns the current step. If no current step is stored in the
+ storage backend, the first step will be returned.
+ """
+ return self._wizard.storage.current_step or self.first
+
+ @property
+ def first(self):
+ "Returns the name of the first step."
+ return self.all[0]
+
+ @property
+ def last(self):
+ "Returns the name of the last step."
+ return self.all[-1]
+
+ @property
+ def next(self):
+ "Returns the next step."
+ return self._wizard.get_next_step()
+
+ @property
+ def prev(self):
+ "Returns the previous step."
+ return self._wizard.get_prev_step()
+
+ @property
+ def index(self):
+ "Returns the index for the current step."
+ return self._wizard.get_step_index()
+
+ @property
+ def step0(self):
+ return int(self.index)
+
+ @property
+ def step1(self):
+ return int(self.index) + 1
+
+
+class WizardView(TemplateView):
+ """
+ The WizardView 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.
+ """
+ storage_name = None
+ form_list = None
+ initial_dict = None
+ instance_dict = None
+ condition_dict = None
+ template_name = 'formtools/wizard/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 wizardview
+ instances for every request. We need to override this method because
+ we add some kwargs which are needed to make the wizardview usable.
+ """
+ initkwargs = cls.get_initkwargs(*args, **kwargs)
+ return super(WizardView, cls).as_view(**initkwargs)
+
+ @classmethod
+ def get_initkwargs(cls, form_list=None, 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 wizardview 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 whose values are model
+ instances if the step is based on a ``ModelForm`` and querysets if
+ the step is based on a ``ModelFormSet``. 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 wizardview 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 kwargs.pop('initial_dict',
+ getattr(cls, 'initial_dict', None)) or {},
+ 'instance_dict': instance_dict or kwargs.pop('instance_dict',
+ getattr(cls, 'instance_dict', None)) or {},
+ 'condition_dict': condition_dict or kwargs.pop('condition_dict',
+ getattr(cls, 'condition_dict', None)) or {}
+ })
+
+ form_list = form_list or kwargs.pop('form_list',
+ getattr(cls, 'form_list', None)) or []
+
+ computed_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.
+ computed_form_list[six.text_type(form[0])] = form[1]
+ else:
+ # if not, add the form with a zero based counter as unicode
+ computed_form_list[six.text_type(i)] = form
+
+ # walk through the new created list of forms
+ for form in six.itervalues(computed_form_list):
+ 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 wizardview (by subclassing).
+ for field in six.itervalues(form.base_fields):
+ if (isinstance(field, forms.FileField) and
+ not hasattr(cls, 'file_storage')):
+ raise NoFileStorageConfigured(
+ "You need to define 'file_storage' in your "
+ "wizard view in order to handle file uploads.")
+
+ # build the kwargs for the wizardview instances
+ kwargs['form_list'] = computed_form_list
+ return kwargs
+
+ def get_prefix(self, *args, **kwargs):
+ # TODO: Add some kind of unique id to prefix
+ return normalize_name(self.__class__.__name__)
+
+ def get_form_list(self):
+ """
+ This method returns a form_list based on the initial form list but
+ checks if there is a condition method/value in the condition_list.
+ If an entry exists in the condition list, it will call/read the value
+ and respect the result. (True means add the form, False means ignore
+ the form)
+
+ The form_list is always generated on the fly because condition methods
+ could use data from other (maybe previous forms).
+ """
+ form_list = SortedDict()
+ for form_key, form_class in six.iteritems(self.form_list):
+ # try to fetch the value from condition list, by default, the form
+ # gets passed to the new list.
+ condition = self.condition_dict.get(form_key, True)
+ if callable(condition):
+ # call the value if needed, passes the current instance.
+ condition = condition(self)
+ if condition:
+ form_list[form_key] = form_class
+ return form_list
+
+ def dispatch(self, request, *args, **kwargs):
+ """
+ This method gets called by the routing engine. The first argument is
+ `request` which contains a `HttpRequest` instance.
+ The request is stored in `self.request` for later use. The storage
+ instance is stored in `self.storage`.
+
+ After processing the request using the `dispatch` method, the
+ response gets updated by the storage engine (for example add cookies).
+ """
+ # add the storage engine to the current wizardview instance
+ self.prefix = self.get_prefix(*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)
+
+ # update the response (e.g. adding cookies)
+ self.storage.update_response(response)
+ return response
+
+ def get(self, request, *args, **kwargs):
+ """
+ This method handles GET requests.
+
+ If a GET request reaches this point, the wizard assumes that the user
+ just starts at the first step or wants to restart the process.
+ The data of the wizard will be resetted before rendering the first step.
+ """
+ self.storage.reset()
+
+ # reset the current step to the first step.
+ self.storage.current_step = self.steps.first
+ return self.render(self.get_form())
+
+ def post(self, *args, **kwargs):
+ """
+ This method handles POST requests.
+
+ The wizard will render either the current step (if form validation
+ wasn't successful), the next step (if the current step was stored
+ successful) or the done view (if no more steps are available)
+ """
+ # Look for a wizard_goto_step element in the posted data which
+ # contains a valid step name. If one was found, render the requested
+ # form. (This makes stepping back a lot easier).
+ wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
+ if wizard_goto_step and wizard_goto_step in self.get_form_list():
+ return self.render_goto_step(wizard_goto_step)
+
+ # Check if form was refreshed
+ management_form = ManagementForm(self.request.POST, prefix=self.prefix)
+ if not management_form.is_valid():
+ raise ValidationError(
+ _('ManagementForm data is missing or has been tampered.'),
+ code='missing_management_form',
+ )
+
+ form_current_step = management_form.cleaned_data['current_step']
+ if (form_current_step != self.steps.current and
+ self.storage.current_step is not None):
+ # form refreshed, change current step
+ self.storage.current_step = form_current_step
+
+ # get the form for the current step
+ form = self.get_form(data=self.request.POST, files=self.request.FILES)
+
+ # and try to validate
+ if form.is_valid():
+ # if the form is valid, store the cleaned data and files.
+ self.storage.set_step_data(self.steps.current, self.process_step(form))
+ self.storage.set_step_files(self.steps.current, self.process_step_files(form))
+
+ # check if the current step is the last step
+ if self.steps.current == self.steps.last:
+ # no more steps, render done view
+ return self.render_done(form, **kwargs)
+ else:
+ # proceed to the next step
+ return self.render_next_step(form)
+ return self.render(form)
+
+ def render_next_step(self, form, **kwargs):
+ """
+ This method gets called when the next step/form should be rendered.
+ `form` contains the last/current form.
+ """
+ # get the form instance based on the data from the storage backend
+ # (if available).
+ next_step = self.steps.next
+ new_form = self.get_form(next_step,
+ data=self.storage.get_step_data(next_step),
+ files=self.storage.get_step_files(next_step))
+
+ # change the stored current step
+ self.storage.current_step = next_step
+ return self.render(new_form, **kwargs)
+
+ def render_goto_step(self, goto_step, **kwargs):
+ """
+ This method gets called when the current step has to be changed.
+ `goto_step` contains the requested step to go to.
+ """
+ self.storage.current_step = goto_step
+ form = self.get_form(
+ data=self.storage.get_step_data(self.steps.current),
+ files=self.storage.get_step_files(self.steps.current))
+ return self.render(form)
+
+ def render_done(self, form, **kwargs):
+ """
+ This method gets called when all forms passed. The method should also
+ re-validate all steps to prevent manipulation. If any form don't
+ validate, `render_revalidation_failure` should get called.
+ If everything is fine call `done`.
+ """
+ final_form_list = []
+ # walk through the form list and try to validate the data again.
+ for form_key in self.get_form_list():
+ form_obj = self.get_form(step=form_key,
+ data=self.storage.get_step_data(form_key),
+ files=self.storage.get_step_files(form_key))
+ if not form_obj.is_valid():
+ return self.render_revalidation_failure(form_key, form_obj, **kwargs)
+ final_form_list.append(form_obj)
+
+ # render the done view and reset the wizard before returning the
+ # response. This is needed to prevent from rendering done with the
+ # same data twice.
+ done_response = self.done(final_form_list, **kwargs)
+ self.storage.reset()
+ return done_response
+
+ def get_form_prefix(self, step=None, form=None):
+ """
+ Returns the prefix which will be used when calling the actual form for
+ the given step. `step` contains the step-name, `form` the form which
+ will be called with the returned prefix.
+
+ If no step is given, the form_prefix will determine the current step
+ automatically.
+ """
+ if step is None:
+ step = self.steps.current
+ return str(step)
+
+ def get_form_initial(self, step):
+ """
+ Returns a dictionary which will be passed to the form for `step`
+ as `initial`. If no initial data was provied while initializing the
+ form wizard, a empty dictionary will be returned.
+ """
+ return self.initial_dict.get(step, {})
+
+ def get_form_instance(self, step):
+ """
+ Returns a object which will be passed to the form for `step`
+ as `instance`. If no instance object was provied while initializing
+ the form wizard, None will be returned.
+ """
+ return self.instance_dict.get(step, None)
+
+ def get_form_kwargs(self, step=None):
+ """
+ Returns the keyword arguments for instantiating the form
+ (or formset) on the given step.
+ """
+ return {}
+
+ def get_form(self, step=None, data=None, files=None):
+ """
+ Constructs the form for a given `step`. If no `step` is defined, the
+ current step will be determined automatically.
+
+ The form will be initialized using the `data` argument to prefill the
+ new form. If needed, instance or queryset (for `ModelForm` or
+ `ModelFormSet`) will be added too.
+ """
+ if step is None:
+ step = self.steps.current
+ # prepare the kwargs for the form instance.
+ kwargs = self.get_form_kwargs(step)
+ kwargs.update({
+ 'data': data,
+ 'files': files,
+ 'prefix': self.get_form_prefix(step, self.form_list[step]),
+ 'initial': self.get_form_initial(step),
+ })
+ if issubclass(self.form_list[step], forms.ModelForm):
+ # If the form is based on ModelForm, add instance if available
+ # and not previously set.
+ kwargs.setdefault('instance', self.get_form_instance(step))
+ elif issubclass(self.form_list[step], forms.models.BaseModelFormSet):
+ # If the form is based on ModelFormSet, add queryset if available
+ # and not previous set.
+ kwargs.setdefault('queryset', self.get_form_instance(step))
+ return self.form_list[step](**kwargs)
+
+ def process_step(self, form):
+ """
+ This method is used to postprocess the form data. By default, it
+ returns the raw `form.data` dictionary.
+ """
+ return self.get_form_step_data(form)
+
+ def process_step_files(self, form):
+ """
+ This method is used to postprocess the form files. By default, it
+ returns the raw `form.files` dictionary.
+ """
+ return self.get_form_step_files(form)
+
+ def render_revalidation_failure(self, step, form, **kwargs):
+ """
+ Gets called when a form doesn't validate when rendering the done
+ view. By default, it changes the current step to failing forms step
+ and renders the form.
+ """
+ self.storage.current_step = step
+ return self.render(form, **kwargs)
+
+ def get_form_step_data(self, form):
+ """
+ Is used to return the raw form data. You may use this method to
+ manipulate the data.
+ """
+ return form.data
+
+ def get_form_step_files(self, form):
+ """
+ Is used to return the raw form files. You may use this method to
+ manipulate the data.
+ """
+ return form.files
+
+ def get_all_cleaned_data(self):
+ """
+ Returns a merged dictionary of all step cleaned_data dictionaries.
+ If a step contains a `FormSet`, the key will be prefixed with
+ 'formset-' and contain a list of the formset cleaned_data dictionaries.
+ """
+ cleaned_data = {}
+ for form_key in self.get_form_list():
+ form_obj = self.get_form(
+ step=form_key,
+ data=self.storage.get_step_data(form_key),
+ files=self.storage.get_step_files(form_key)
+ )
+ if form_obj.is_valid():
+ if isinstance(form_obj.cleaned_data, (tuple, list)):
+ cleaned_data.update({
+ 'formset-%s' % form_key: form_obj.cleaned_data
+ })
+ else:
+ cleaned_data.update(form_obj.cleaned_data)
+ return cleaned_data
+
+ def get_cleaned_data_for_step(self, step):
+ """
+ Returns the cleaned data for a given `step`. Before returning the
+ cleaned data, the stored values are revalidated through the form.
+ If the data doesn't validate, None will be returned.
+ """
+ if step in self.form_list:
+ form_obj = self.get_form(step=step,
+ data=self.storage.get_step_data(step),
+ files=self.storage.get_step_files(step))
+ if form_obj.is_valid():
+ return form_obj.cleaned_data
+ return None
+
+ def get_next_step(self, step=None):
+ """
+ Returns the next step after the given `step`. If no more steps are
+ available, None will be returned. If the `step` argument is None, the
+ current step will be determined automatically.
+ """
+ if step is None:
+ step = self.steps.current
+ form_list = self.get_form_list()
+ key = form_list.keyOrder.index(step) + 1
+ if len(form_list.keyOrder) > key:
+ return form_list.keyOrder[key]
+ return None
+
+ def get_prev_step(self, step=None):
+ """
+ Returns the previous step before the given `step`. If there are no
+ steps available, None will be returned. If the `step` argument is
+ None, the current step will be determined automatically.
+ """
+ if step is None:
+ step = self.steps.current
+ form_list = self.get_form_list()
+ key = form_list.keyOrder.index(step) - 1
+ if key >= 0:
+ return form_list.keyOrder[key]
+ return None
+
+ def get_step_index(self, step=None):
+ """
+ Returns the index for the given `step` name. If no step is given,
+ the current step will be used to get the index.
+ """
+ if step is None:
+ step = self.steps.current
+ return self.get_form_list().keyOrder.index(step)
+
+ def get_context_data(self, form, **kwargs):
+ """
+ Returns the template context for a step. You can overwrite this method
+ to add more data for all or some steps. This method returns a
+ dictionary containing the rendered form step. Available template
+ context variables are:
+
+ * all extra data stored in the storage backend
+ * `wizard` - a dictionary representation of the wizard instance
+
+ Example:
+
+ .. code-block:: python
+
+ class MyWizard(WizardView):
+ def get_context_data(self, form, **kwargs):
+ context = super(MyWizard, self).get_context_data(form=form, **kwargs)
+ if self.steps.current == 'my_step_name':
+ context.update({'another_var': True})
+ return context
+ """
+ context = super(WizardView, self).get_context_data(form=form, **kwargs)
+ context.update(self.storage.extra_data)
+ context['wizard'] = {
+ 'form': form,
+ 'steps': self.steps,
+ 'management_form': ManagementForm(prefix=self.prefix, initial={
+ 'current_step': self.steps.current,
+ }),
+ }
+ return context
+
+ def render(self, form=None, **kwargs):
+ """
+ Returns a ``HttpResponse`` containing all needed context data.
+ """
+ form = form or self.get_form()
+ context = self.get_context_data(form=form, **kwargs)
+ return self.render_to_response(context)
+
+ def done(self, form_list, **kwargs):
+ """
+ This method must be overridden by a subclass to process to form data
+ after processing all steps.
+ """
+ raise NotImplementedError("Your %s class has not defined a done() "
+ "method, which is required." % self.__class__.__name__)
+
+
+class SessionWizardView(WizardView):
+ """
+ A WizardView with pre-configured SessionStorage backend.
+ """
+ storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage'
+
+
+class CookieWizardView(WizardView):
+ """
+ A WizardView with pre-configured CookieStorage backend.
+ """
+ storage_name = 'django.contrib.formtools.wizard.storage.cookie.CookieStorage'
+
+
+class NamedUrlWizardView(WizardView):
+ """
+ A WizardView with URL named steps support.
+ """
+ url_name = None
+ done_step_name = None
+
+ @classmethod
+ def get_initkwargs(cls, *args, **kwargs):
+ """
+ We require a url_name to reverse URLs later. Additionally users can
+ pass a done_step_name to change the URL name of the "done" view.
+ """
+ assert 'url_name' in kwargs, 'URL name is needed to resolve correct wizard URLs'
+ extra_kwargs = {
+ 'done_step_name': kwargs.pop('done_step_name', 'done'),
+ 'url_name': kwargs.pop('url_name'),
+ }
+ initkwargs = super(NamedUrlWizardView, cls).get_initkwargs(*args, **kwargs)
+ initkwargs.update(extra_kwargs)
+
+ assert initkwargs['done_step_name'] not in initkwargs['form_list'], \
+ 'step name "%s" is reserved for "done" view' % initkwargs['done_step_name']
+ return initkwargs
+
+ def get_step_url(self, step):
+ return reverse(self.url_name, kwargs={'step': step})
+
+ def get(self, *args, **kwargs):
+ """
+ This renders the form or, if needed, does the http redirects.
+ """
+ step_url = kwargs.get('step', None)
+ if step_url is None:
+ if 'reset' in self.request.GET:
+ self.storage.reset()
+ self.storage.current_step = self.steps.first
+ if self.request.GET:
+ query_string = "?%s" % self.request.GET.urlencode()
+ else:
+ query_string = ""
+ return redirect(self.get_step_url(self.steps.current)
+ + query_string)
+
+ # is the current step the "done" name/view?
+ elif step_url == self.done_step_name:
+ last_step = self.steps.last
+ return self.render_done(self.get_form(step=last_step,
+ data=self.storage.get_step_data(last_step),
+ files=self.storage.get_step_files(last_step)
+ ), **kwargs)
+
+ # is the url step name not equal to the step in the storage?
+ # if yes, change the step in the storage (if name exists)
+ elif step_url == self.steps.current:
+ # URL step name and storage step name are equal, render!
+ return self.render(self.get_form(
+ data=self.storage.current_step_data,
+ files=self.storage.current_step_files,
+ ), **kwargs)
+
+ elif step_url in self.get_form_list():
+ self.storage.current_step = step_url
+ return self.render(self.get_form(
+ data=self.storage.current_step_data,
+ files=self.storage.current_step_files,
+ ), **kwargs)
+
+ # invalid step name, reset to first and redirect.
+ else:
+ self.storage.current_step = self.steps.first
+ return redirect(self.get_step_url(self.steps.first))
+
+ def post(self, *args, **kwargs):
+ """
+ Do a redirect if user presses the prev. step button. The rest of this
+ is super'd from WizardView.
+ """
+ wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
+ if wizard_goto_step and wizard_goto_step in self.get_form_list():
+ return self.render_goto_step(wizard_goto_step)
+ return super(NamedUrlWizardView, self).post(*args, **kwargs)
+
+ def get_context_data(self, form, **kwargs):
+ """
+ NamedUrlWizardView provides the url_name of this wizard in the context
+ dict `wizard`.
+ """
+ context = super(NamedUrlWizardView, self).get_context_data(form=form, **kwargs)
+ context['wizard']['url_name'] = self.url_name
+ return context
+
+ def render_next_step(self, form, **kwargs):
+ """
+ When using the NamedUrlWizardView, we have to redirect to update the
+ browser's URL to match the shown step.
+ """
+ next_step = self.get_next_step()
+ self.storage.current_step = next_step
+ return redirect(self.get_step_url(next_step))
+
+ def render_goto_step(self, goto_step, **kwargs):
+ """
+ This method gets called when the current step has to be changed.
+ `goto_step` contains the requested step to go to.
+ """
+ self.storage.current_step = goto_step
+ return redirect(self.get_step_url(goto_step))
+
+ def render_revalidation_failure(self, failed_step, form, **kwargs):
+ """
+ When a step fails, we have to redirect the user to the first failing
+ step.
+ """
+ self.storage.current_step = failed_step
+ return redirect(self.get_step_url(failed_step))
+
+ def render_done(self, form, **kwargs):
+ """
+ When rendering the done view, we have to redirect first (if the URL
+ name doesn't fit).
+ """
+ if kwargs.get('step', None) != self.done_step_name:
+ return redirect(self.get_step_url(self.done_step_name))
+ return super(NamedUrlWizardView, self).render_done(form, **kwargs)
+
+
+class NamedUrlSessionWizardView(NamedUrlWizardView):
+ """
+ A NamedUrlWizardView with pre-configured SessionStorage backend.
+ """
+ storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage'
+
+
+class NamedUrlCookieWizardView(NamedUrlWizardView):
+ """
+ A NamedUrlFormWizard with pre-configured CookieStorageBackend.
+ """
+ storage_name = 'django.contrib.formtools.wizard.storage.cookie.CookieStorage'