mirror of
				https://github.com/django/django.git
				synced 2025-10-28 08:06:09 +00:00 
			
		
		
		
	git-svn-id: http://code.djangoproject.com/svn/django/trunk@17235 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			610 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			610 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ===========
 | |
| Form wizard
 | |
| ===========
 | |
| 
 | |
| .. module:: django.contrib.formtools.wizard.views
 | |
|     :synopsis: Splits forms across multiple Web pages.
 | |
| 
 | |
| Django comes with an optional "form wizard" application that splits
 | |
| :doc:`forms </topics/forms/index>` across multiple Web pages. It maintains
 | |
| state in one of the backends so that the full server-side processing can be
 | |
| delayed until the submission of the final form.
 | |
| 
 | |
| You might want to use this if you have a lengthy form that would be too
 | |
| unwieldy for display on a single page. The first page might ask the user for
 | |
| core information, the second page might ask for less important information,
 | |
| etc.
 | |
| 
 | |
| The term "wizard", in this context, is `explained on Wikipedia`_.
 | |
| 
 | |
| .. _explained on Wikipedia: http://en.wikipedia.org/wiki/Wizard_%28software%29
 | |
| 
 | |
| How it works
 | |
| ============
 | |
| 
 | |
| Here's the basic workflow for how a user would use a wizard:
 | |
| 
 | |
| 1. The user visits the first page of the wizard, fills in the form and
 | |
|    submits it.
 | |
| 2. The server validates the data. If it's invalid, the form is displayed
 | |
|    again, with error messages. If it's valid, the server saves the current
 | |
|    state of the wizard in the backend and redirects to the next step.
 | |
| 3. Step 1 and 2 repeat, for every subsequent form in the wizard.
 | |
| 4. Once the user has submitted all the forms and all the data has been
 | |
|    validated, the wizard processes the data -- saving it to the database,
 | |
|    sending an email, or whatever the application needs to do.
 | |
| 
 | |
| Usage
 | |
| =====
 | |
| 
 | |
| This application handles as much machinery for you as possible. Generally,
 | |
| you just have to do these things:
 | |
| 
 | |
| 1. Define a number of :class:`~django.forms.Form` classes -- one per
 | |
|    wizard page.
 | |
| 
 | |
| 2. Create a :class:`WizardView` subclass that specifies what to do once
 | |
|    all of your forms have been submitted and validated. This also lets
 | |
|    you override some of the wizard's behavior.
 | |
| 
 | |
| 3. Create some templates that render the forms. You can define a single,
 | |
|    generic template to handle every one of the forms, or you can define a
 | |
|    specific template for each form.
 | |
| 
 | |
| 4. Add ``django.contrib.formtools`` to your
 | |
|    :setting:`INSTALLED_APPS` list in your settings file.
 | |
| 
 | |
| 5. Point your URLconf at your :class:`WizardView` :meth:`~WizardView.as_view` method.
 | |
| 
 | |
| Defining ``Form`` classes
 | |
| -------------------------
 | |
| 
 | |
| The first step in creating a form wizard is to create the
 | |
| :class:`~django.forms.Form` classes.  These should be standard
 | |
| :class:`django.forms.Form` classes, covered in the :doc:`forms documentation
 | |
| </topics/forms/index>`.  These classes can live anywhere in your codebase,
 | |
| but convention is to put them in a file called :file:`forms.py` in your
 | |
| application.
 | |
| 
 | |
| For example, let's write a "contact form" wizard, where the first page's form
 | |
| collects the sender's email address and subject, and the second page collects
 | |
| the message itself. Here's what the :file:`forms.py` might look like::
 | |
| 
 | |
|     from django import forms
 | |
| 
 | |
|     class ContactForm1(forms.Form):
 | |
|         subject = forms.CharField(max_length=100)
 | |
|         sender = forms.EmailField()
 | |
| 
 | |
|     class ContactForm2(forms.Form):
 | |
|         message = forms.CharField(widget=forms.Textarea)
 | |
| 
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     In order to use :class:`~django.forms.FileField` in any form, see the
 | |
|     section :ref:`Handling files <wizard-files>` below to learn more about
 | |
|     what to do.
 | |
| 
 | |
| Creating a ``WizardView`` class
 | |
| -------------------------------
 | |
| 
 | |
| The next step is to create a
 | |
| :class:`django.contrib.formtools.wizard.views.WizardView` subclass. You can
 | |
| also use the :class:`SessionWizardView` or :class:`CookieWizardView` classes
 | |
| which preselect the backend used for storing information during execution of the
 | |
| wizard (as their names indicate, server-side sessions and browser cookies
 | |
| respectively).
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     To use the :class:`SessionWizardView` follow the instructions
 | |
|     in the :doc:`sessions documentation </topics/http/sessions>` on
 | |
|     how to enable sessions.
 | |
| 
 | |
| We will use the :class:`SessionWizardView` in all examples but is is completely
 | |
| fine to use the :class:`CookieWizardView` instead. As with your
 | |
| :class:`~django.forms.Form` classes, this :class:`WizardView` class can live
 | |
| anywhere in your codebase, but convention is to put it in :file:`views.py`.
 | |
| 
 | |
| The only requirement on this subclass is that it implement a
 | |
| :meth:`~WizardView.done()` method.
 | |
| 
 | |
| .. method:: WizardView.done(form_list)
 | |
| 
 | |
|     This method specifies what should happen when the data for *every* form is
 | |
|     submitted and validated. This method is passed a list of validated
 | |
|     :class:`~django.forms.Form` instances.
 | |
| 
 | |
|     In this simplistic example, rather than performing any database operation,
 | |
|     the method simply renders a template of the validated data::
 | |
| 
 | |
|         from django.shortcuts import render_to_response
 | |
|         from django.contrib.formtools.wizard.views import SessionWizardView
 | |
| 
 | |
|         class ContactWizard(SessionWizardView):
 | |
|             def done(self, form_list, **kwargs):
 | |
|                 return render_to_response('done.html', {
 | |
|                     'form_data': [form.cleaned_data for form in form_list],
 | |
|                 })
 | |
| 
 | |
|     Note that this method will be called via ``POST``, so it really ought to be a
 | |
|     good Web citizen and redirect after processing the data. Here's another
 | |
|     example::
 | |
| 
 | |
|         from django.http import HttpResponseRedirect
 | |
|         from django.contrib.formtools.wizard.views import SessionWizardView
 | |
| 
 | |
|         class ContactWizard(SessionWizardView):
 | |
|             def done(self, form_list, **kwargs):
 | |
|                 do_something_with_the_form_data(form_list)
 | |
|                 return HttpResponseRedirect('/page-to-redirect-to-when-done/')
 | |
| 
 | |
| See the section :ref:`Advanced WizardView methods <wizardview-advanced-methods>`
 | |
| below to learn about more :class:`WizardView` hooks.
 | |
| 
 | |
| Creating templates for the forms
 | |
| --------------------------------
 | |
| 
 | |
| Next, you'll need to create a template that renders the wizard's forms. By
 | |
| default, every form uses a template called
 | |
| :file:`formtools/wizard/wizard_form.html`. You can change this template name
 | |
| by overriding either the
 | |
| :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` attribute
 | |
| or the
 | |
| :meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names()`
 | |
| method, which are documented in the
 | |
| :class:`~django.views.generic.base.TemplateResponseMixin` documentation.  The
 | |
| latter one allows you to use a different template for each form.
 | |
| 
 | |
| This template expects a ``wizard`` object that has various items attached to
 | |
| it:
 | |
| 
 | |
| * ``form`` -- The :class:`~django.forms.Form` or
 | |
|   :class:`~django.forms.formset.BaseFormSet` instance for the current step
 | |
|   (either empty or with errors).
 | |
| 
 | |
| * ``steps`` -- A helper object to access the various steps related data:
 | |
| 
 | |
|   * ``step0`` -- The current step (zero-based).
 | |
|   * ``step1`` -- The current step (one-based).
 | |
|   * ``count`` -- The total number of steps.
 | |
|   * ``first`` -- The first step.
 | |
|   * ``last`` -- The last step.
 | |
|   * ``current`` -- The current (or first) step.
 | |
|   * ``next`` -- The next step.
 | |
|   * ``prev`` -- The previous step.
 | |
|   * ``index`` -- The index of the current step.
 | |
|   * ``all`` -- A list of all steps of the wizard.
 | |
| 
 | |
| You can supply additional context variables by using the
 | |
| :meth:`~WizardView.get_context_data` method of your :class:`WizardView`
 | |
| subclass.
 | |
| 
 | |
| Here's a full example template:
 | |
| 
 | |
| .. code-block:: html+django
 | |
| 
 | |
|     {% extends "base.html" %}
 | |
| 
 | |
|     {% block head %}
 | |
|     {{ wizard.form.media }}
 | |
|     {% endblock %}
 | |
| 
 | |
|     {% block content %}
 | |
|     <p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
 | |
|     <form action="" method="post">{% csrf_token %}
 | |
|     <table>
 | |
|     {{ wizard.management_form }}
 | |
|     {% if wizard.form.forms %}
 | |
|         {{ wizard.form.management_form }}
 | |
|         {% for form in wizard.form.forms %}
 | |
|             {{ form }}
 | |
|         {% endfor %}
 | |
|     {% else %}
 | |
|         {{ wizard.form }}
 | |
|     {% endif %}
 | |
|     </table>
 | |
|     {% if wizard.steps.prev %}
 | |
|     <button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
 | |
|     <button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
 | |
|     {% endif %}
 | |
|     <input type="submit" value="{% trans "submit" %}"/>
 | |
|     </form>
 | |
|     {% endblock %}
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     Note that ``{{ wizard.management_form }}`` **must be used** for
 | |
|     the wizard to work properly.
 | |
| 
 | |
| .. _wizard-urlconf:
 | |
| 
 | |
| Hooking the wizard into a URLconf
 | |
| ---------------------------------
 | |
| 
 | |
| Finally, we need to specify which forms to use in the wizard, and then
 | |
| deploy the new :class:`WizardView` object at an URL in the ``urls.py``. The
 | |
| wizard's :meth:`as_view` method takes a list of your
 | |
| :class:`~django.forms.Form` classes as an argument during instantiation::
 | |
| 
 | |
|     from django.conf.urls import patterns
 | |
| 
 | |
|     from myapp.forms import ContactForm1, ContactForm2
 | |
|     from myapp.views import ContactWizard
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         (r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
 | |
|     )
 | |
| 
 | |
| .. _wizardview-advanced-methods:
 | |
| 
 | |
| Advanced ``WizardView`` methods
 | |
| ===============================
 | |
| 
 | |
| .. class:: WizardView
 | |
| 
 | |
|     Aside from the :meth:`~done()` method, :class:`WizardView` offers a few
 | |
|     advanced method hooks that let you customize how your wizard works.
 | |
| 
 | |
|     Some of these methods take an argument ``step``, which is a zero-based
 | |
|     counter as string representing the current step of the wizard. (E.g., the
 | |
|     first form is ``'0'`` and the second form is ``'1'``)
 | |
| 
 | |
| .. method:: WizardView.get_form_prefix(step)
 | |
| 
 | |
|     Given the step, returns a form prefix to use. By default, this simply uses
 | |
|     the step itself. For more, see the :ref:`form prefix documentation
 | |
|     <form-prefix>`.
 | |
| 
 | |
| .. method:: WizardView.get_form_initial(step)
 | |
| 
 | |
|     Returns a dictionary which will be passed as the
 | |
|     :attr:`~django.forms.Form.initial` argument when instantiating the Form
 | |
|     instance for step ``step``. If no initial data was provided while
 | |
|     initializing the form wizard, an empty dictionary should be returned.
 | |
| 
 | |
|     The default implementation::
 | |
| 
 | |
|         def get_form_initial(self, step):
 | |
|             return self.initial_dict.get(step, {})
 | |
| 
 | |
| .. method:: WizardView.get_form_kwargs(step)
 | |
| 
 | |
|     Returns a dictionary which will be used as the keyword arguments when
 | |
|     instantiating the form instance on given ``step``.
 | |
| 
 | |
|     The default implementation::
 | |
| 
 | |
|         def get_form_kwargs(self, step):
 | |
|             return {}
 | |
| 
 | |
| .. method:: WizardView.get_form_instance(step)
 | |
| 
 | |
|     This method will be called only if a :class:`~django.forms.ModelForm` is
 | |
|     used as the form for step ``step``.
 | |
| 
 | |
|     Returns an :class:`~django.db.models.Model` object which will be passed as
 | |
|     the :attr:`~django.forms.ModelForm.instance` argument when instantiating the
 | |
|     ModelForm for step ``step``.  If no instance object was provided while
 | |
|     initializing the form wizard, ``None`` will be returned.
 | |
| 
 | |
|     The default implementation::
 | |
| 
 | |
|         def get_form_instance(self, step):
 | |
|             return self.instance_dict.get(step, None)
 | |
| 
 | |
| .. method:: WizardView.get_context_data(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.
 | |
| 
 | |
|     The default template context variables are:
 | |
| 
 | |
|     * Any extra data the storage backend has stored
 | |
|     * ``form`` -- form instance of the current step
 | |
|     * ``wizard`` -- the wizard instance itself
 | |
| 
 | |
|     Example to add extra variables for a specific step::
 | |
| 
 | |
|         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
 | |
| 
 | |
| .. method:: WizardView.get_prefix(*args, **kwargs)
 | |
| 
 | |
|     This method returns a prefix for use by the storage backends. Backends use
 | |
|     the prefix as a mechanism to allow data to be stored separately for each
 | |
|     wizard. This allows wizards to store their data in a single backend
 | |
|     without overwriting each other.
 | |
| 
 | |
|     You can change this method to make the wizard data prefix more unique to,
 | |
|     e.g. have multiple instances of one wizard in one session.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def get_prefix(self, *args, **kwargs):
 | |
|             # use the lowercase underscore version of the class name
 | |
|             return normalize_name(self.__class__.__name__)
 | |
| 
 | |
| .. method:: WizardView.get_form(step=None, data=None, files=None)
 | |
| 
 | |
|     This method constructs the form for a given ``step``. If no ``step`` is
 | |
|     defined, the current step will be determined automatically.
 | |
|     The method gets three arguments:
 | |
| 
 | |
|     * ``step`` -- The step for which the form instance should be generated.
 | |
|     * ``data`` -- Gets passed to the form's data argument
 | |
|     * ``files`` -- Gets passed to the form's files argument
 | |
| 
 | |
|     You can override this method to add extra arguments to the form instance.
 | |
| 
 | |
|     Example code to add a user attribute to the form on step 2::
 | |
| 
 | |
|         def get_form(self, step=None, data=None, files=None):
 | |
|             form = super(MyWizard, self).get_form(step, data, files)
 | |
|             if step == '1':
 | |
|                 form.user = self.request.user
 | |
|             return form
 | |
| 
 | |
| .. method:: WizardView.process_step(form)
 | |
| 
 | |
|     Hook for modifying the wizard's internal state, given a fully validated
 | |
|     :class:`~django.forms.Form` object. The Form is guaranteed to have clean,
 | |
|     valid data.
 | |
| 
 | |
|     This method gives you a way to post-process the form data before the data
 | |
|     gets stored within the storage backend. By default it just returns the
 | |
|     ``form.data`` dictionary. You should not manipulate the data here but you
 | |
|     can use it to do some extra work if needed (e.g. set storage extra data).
 | |
| 
 | |
|     Note that this method is called every time a page is rendered for *all*
 | |
|     submitted steps.
 | |
| 
 | |
|     The default implementation::
 | |
| 
 | |
|         def process_step(self, form):
 | |
|             return self.get_form_step_data(form)
 | |
| 
 | |
| .. method:: WizardView.process_step_files(form)
 | |
| 
 | |
|     This method gives you a way to post-process the form files before the
 | |
|     files gets stored within the storage backend. By default it just returns
 | |
|     the ``form.files`` dictionary. You should not manipulate the data here
 | |
|     but you can use it to do some extra work if needed (e.g. set storage
 | |
|     extra data).
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def process_step_files(self, form):
 | |
|             return self.get_form_step_files(form)
 | |
| 
 | |
| .. method:: WizardView.render_revalidation_failure(step, form, **kwargs)
 | |
| 
 | |
|     When the wizard thinks all steps have passed it revalidates all forms with
 | |
|     the data from the backend storage.
 | |
| 
 | |
|     If any of the forms don't validate correctly, this method gets called.
 | |
|     This method expects two arguments, ``step`` and ``form``.
 | |
| 
 | |
|     The default implementation resets the current step to the first failing
 | |
|     form and redirects the user to the invalid form.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def render_revalidation_failure(self, step, form, **kwargs):
 | |
|             self.storage.current_step = step
 | |
|             return self.render(form, **kwargs)
 | |
| 
 | |
| .. method:: WizardView.get_form_step_data(form)
 | |
| 
 | |
|     This method fetches the data from the ``form`` Form instance and returns the
 | |
|     dictionary. You can use this method to manipulate the values before the data
 | |
|     gets stored in the storage backend.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def get_form_step_data(self, form):
 | |
|             return form.data
 | |
| 
 | |
| .. method:: WizardView.get_form_step_files(form)
 | |
| 
 | |
|     This method returns the form files. You can use this method to manipulate
 | |
|     the files before the data gets stored in the storage backend.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def get_form_step_files(self, form):
 | |
|             return form.files
 | |
| 
 | |
| .. method:: WizardView.render(form, **kwargs)
 | |
| 
 | |
|     This method gets called after the GET or POST request has been handled. You
 | |
|     can hook in this method to, e.g. change the type of HTTP response.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def render(self, form=None, **kwargs):
 | |
|             form = form or self.get_form()
 | |
|             context = self.get_context_data(form=form, **kwargs)
 | |
|             return self.render_to_response(context)
 | |
| 
 | |
| Providing initial data for the forms
 | |
| ====================================
 | |
| 
 | |
| .. attribute:: WizardView.initial_dict
 | |
| 
 | |
|     Initial data for a wizard's :class:`~django.forms.Form` objects can be
 | |
|     provided using the optional :attr:`~Wizard.initial_dict` keyword argument.
 | |
|     This argument should be a dictionary mapping the steps to dictionaries
 | |
|     containing the initial data for each step. The dictionary of initial data
 | |
|     will be passed along to the constructor of the step's
 | |
|     :class:`~django.forms.Form`::
 | |
| 
 | |
|         >>> from myapp.forms import ContactForm1, ContactForm2
 | |
|         >>> from myapp.views import ContactWizard
 | |
|         >>> initial = {
 | |
|         ...     '0': {'subject': 'Hello', 'sender': 'user@example.com'},
 | |
|         ...     '1': {'message': 'Hi there!'}
 | |
|         ... }
 | |
|         >>> wiz = ContactWizard.as_view([ContactForm1, ContactForm2], initial_dict=initial)
 | |
|         >>> form1 = wiz.get_form('0')
 | |
|         >>> form2 = wiz.get_form('1')
 | |
|         >>> form1.initial
 | |
|         {'sender': 'user@example.com', 'subject': 'Hello'}
 | |
|         >>> form2.initial
 | |
|         {'message': 'Hi there!'}
 | |
| 
 | |
|     The ``initial_dict`` can also take a list of dictionaries for a specific
 | |
|     step if the step is a ``FormSet``.
 | |
| 
 | |
| .. _wizard-files:
 | |
| 
 | |
| Handling files
 | |
| ==============
 | |
| 
 | |
| To handle :class:`~django.forms.FileField` within any step form of the wizard,
 | |
| you have to add a :attr:`file_storage` to your :class:`WizardView` subclass.
 | |
| 
 | |
| This storage will temporarily store the uploaded files for the wizard. The
 | |
| :attr:`file_storage` attribute should be a
 | |
| :class:`~django.core.files.storage.Storage` subclass.
 | |
| 
 | |
| .. warning::
 | |
| 
 | |
|     Please remember to take care of removing old files as the
 | |
|     :class:`WizardView` won't remove any files, whether the wizard gets
 | |
|     finished correctly or not.
 | |
| 
 | |
| Conditionally view/skip specific steps
 | |
| ======================================
 | |
| 
 | |
| .. attribute:: WizardView.condition_dict
 | |
| 
 | |
| The :meth:`~WizardView.as_view` method accepts a ``condition_dict`` argument.
 | |
| You can pass a dictionary of boolean values or callables. The key should match
 | |
| the steps names (e.g. '0', '1').
 | |
| 
 | |
| If the value of a specific step is callable it will be called with the
 | |
| :class:`WizardView` instance as the only argument. If the return value is true,
 | |
| the step's form will be used.
 | |
| 
 | |
| This example provides a contact form including a condition. The condition is
 | |
| used to show a message form only if a checkbox in the first step was checked.
 | |
| 
 | |
| The steps are defined in a ``forms.py`` file::
 | |
| 
 | |
|     from django import forms
 | |
| 
 | |
|     class ContactForm1(forms.Form):
 | |
|         subject = forms.CharField(max_length=100)
 | |
|         sender = forms.EmailField()
 | |
|         leave_message = forms.BooleanField(required=False)
 | |
| 
 | |
|     class ContactForm2(forms.Form):
 | |
|         message = forms.CharField(widget=forms.Textarea)
 | |
| 
 | |
| We define our wizard in a ``views.py``::
 | |
| 
 | |
|     from django.shortcuts import render_to_response
 | |
|     from django.contrib.formtools.wizard.views import SessionWizardView
 | |
| 
 | |
|     def show_message_form_condition(wizard):
 | |
|         # try to get the cleaned data of step 1
 | |
|         cleaned_data = wizard.get_cleaned_data_for_step('0') or {}
 | |
|         # check if the field ``leave_message`` was checked.
 | |
|         return cleaned_data.get('leave_message', True)
 | |
| 
 | |
|     class ContactWizard(SessionWizardView):
 | |
| 
 | |
|         def done(self, form_list, **kwargs):
 | |
|             return render_to_response('done.html', {
 | |
|                 'form_data': [form.cleaned_data for form in form_list],
 | |
|             })
 | |
| 
 | |
| We need to add the ``ContactWizard`` to our ``urls.py`` file::
 | |
| 
 | |
|     from django.conf.urls import pattern
 | |
| 
 | |
|     from myapp.forms import ContactForm1, ContactForm2
 | |
|     from myapp.views import ContactWizard, show_message_form_condition
 | |
| 
 | |
|     contact_forms = [ContactForm1, ContactForm2]
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         (r'^contact/$', ContactWizard.as_view(contact_forms,
 | |
|             condition_dict={'1': show_message_form_condition}
 | |
|         )),
 | |
|     )
 | |
| 
 | |
| As you can see, we defined a ``show_message_form_condition`` next to our
 | |
| :class:`WizardView` subclass and added a ``condition_dict`` argument to the
 | |
| :meth:`~WizardView.as_view` method. The key refers to the second wizard step
 | |
| (because of the zero based step index).
 | |
| 
 | |
| How to work with ModelForm and ModelFormSet
 | |
| ===========================================
 | |
| 
 | |
| .. attribute:: WizardView.instance_dict
 | |
| 
 | |
| WizardView supports :doc:`ModelForms </topics/forms/modelforms>` and
 | |
| :ref:`ModelFormSets <model-formsets>`. Additionally to
 | |
| :attr:`~WizardView.initial_dict`, the :meth:`~WizardView.as_view` method takes
 | |
| an ``instance_dict`` argument that should contain instances of ``ModelForm`` and
 | |
| ``ModelFormSet``.  Similarly to :attr:`~WizardView.initial_dict`, these
 | |
| dictionary key values should be equal to the step number in the form list.
 | |
| 
 | |
| Usage of ``NamedUrlWizardView``
 | |
| ===============================
 | |
| 
 | |
| .. class:: NamedUrlWizardView
 | |
| 
 | |
| There is a :class:`WizardView` subclass which adds named-urls support to the wizard.
 | |
| By doing this, you can have single urls for every step.
 | |
| 
 | |
| To use the named urls, you have to change the ``urls.py``.
 | |
| 
 | |
| Below you will see an example of a contact wizard with two steps, step 1 with
 | |
| "contactdata" as its name and step 2 with "leavemessage" as its name.
 | |
| 
 | |
| Additionally you have to pass two more arguments to the
 | |
| :meth:`~WizardView.as_view` method:
 | |
| 
 | |
| * ``url_name`` -- the name of the url (as provided in the urls.py)
 | |
| * ``done_step_name`` -- the name in the url for the done step
 | |
| 
 | |
| Example code for the changed ``urls.py`` file::
 | |
| 
 | |
|     from django.conf.urls import url, patterns
 | |
| 
 | |
|     from myapp.forms import ContactForm1, ContactForm2
 | |
|     from myapp.views import ContactWizard
 | |
| 
 | |
|     named_contact_forms = (
 | |
|         ('contactdata', ContactForm1),
 | |
|         ('leavemessage', ContactForm2),
 | |
|     )
 | |
| 
 | |
|     contact_wizard = ContactWizard.as_view(named_contact_forms,
 | |
|         url_name='contact_step', done_step_name='finished')
 | |
| 
 | |
|     urlpatterns = patterns('',
 | |
|         url(r'^contact/(?P<step>.+)/$', contact_wizard, name='contact_step'),
 | |
|         url(r'^contact/$', contact_wizard, name='contact'),
 | |
|     )
 | |
| 
 | |
| Advanced ``NamedUrlWizardView`` methods
 | |
| =======================================
 | |
| 
 | |
| .. method:: NamedUrlWizardView.get_step_url(step)
 | |
| 
 | |
|     This method returns the URL for a specific step.
 | |
| 
 | |
|     Default implementation::
 | |
| 
 | |
|         def get_step_url(self, step):
 | |
|             return reverse(self.url_name, kwargs={'step': step})
 |