Form wizard documentation tweaks:

* Simplified Sphinx references to FormWizard class.
  * Wrapped long lines.
  * Added references to template loader functions.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@11986 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Gary Wilson Jr 2009-12-25 21:07:11 +00:00
parent b4f5e80cd1
commit 6154d58cb5
1 changed files with 73 additions and 79 deletions

View File

@ -47,36 +47,34 @@ Usage
This application handles as much machinery for you as possible. Generally, you This application handles as much machinery for you as possible. Generally, you
just have to do these things: just have to do these things:
1. Define a number of :mod:`django.forms` 1. Define a number of :class:`~django.forms.Form` classes -- one per wizard
:class:`~django.forms.forms.Form` classes -- one per wizard page. page.
2. Create a :class:`~django.contrib.formtools.wizard.FormWizard` class 2. Create a :class:`FormWizard` class that specifies what to do once all of
that specifies what to do once all of your forms have been submitted your forms have been submitted and validated. This also lets you
and validated. This also lets you override some of the wizard's behavior. override some of the wizard's behavior.
3. Create some templates that render the forms. You can define a single, 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 generic template to handle every one of the forms, or you can define a
specific template for each form. specific template for each form.
4. Point your URLconf at your 4. Point your URLconf at your :class:`FormWizard` class.
:class:`~django.contrib.formtools.wizard.FormWizard` class.
Defining ``Form`` classes Defining ``Form`` classes
========================= =========================
The first step in creating a form wizard is to create the :class:`~django.forms.forms.Form` classes. The first step in creating a form wizard is to create the
These should be standard :mod:`django.forms` :class:`~django.forms.Form` classes. These should be standard
:class:`~django.forms.forms.Form` classes, covered in the :class:`django.forms.Form` classes, covered in the :ref:`forms documentation
:ref:`forms documentation <topics-forms-index>`. <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
These classes can live anywhere in your codebase, but convention is to put them application.
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 For example, let's write a "contact form" wizard, where the first page's form
collects the sender's e-mail address and subject, and the second page collects collects the sender's e-mail address and subject, and the second page collects
the message itself. Here's what the :file:`forms.py` might look like:: the message itself. Here's what the :file:`forms.py` might look like::
from django import forms from django import forms
class ContactForm1(forms.Form): class ContactForm1(forms.Form):
subject = forms.CharField(max_length=100) subject = forms.CharField(max_length=100)
@ -86,27 +84,27 @@ the message itself. Here's what the :file:`forms.py` might look like::
message = forms.CharField(widget=forms.Textarea) message = forms.CharField(widget=forms.Textarea)
**Important limitation:** Because the wizard uses HTML hidden fields to store **Important limitation:** Because the wizard uses HTML hidden fields to store
data between pages, you may not include a :class:`~django.forms.fields.FileField` data between pages, you may not include a :class:`~django.forms.FileField`
in any form except the last one. in any form except the last one.
Creating a ``FormWizard`` class Creating a ``FormWizard`` class
=============================== ===============================
The next step is to create a :class:`~django.contrib.formtools.wizard.FormWizard` The next step is to create a
class, which should be a subclass of ``django.contrib.formtools.wizard.FormWizard``. :class:`django.contrib.formtools.wizard.FormWizard` subclass. As with your
:class:`~django.forms.Form` classes, this :class:`FormWizard` class can live
As with your :class:`~django.forms.forms.Form` classes, this anywhere in your codebase, but convention is to put it in :file:`forms.py`.
:class:`~django.contrib.formtools.wizard.FormWizard` class can live anywhere
in your codebase, but convention is to put it in :file:`forms.py`.
The only requirement on this subclass is that it implement a The only requirement on this subclass is that it implement a
:meth:`~django.contrib.formtools.wizard.FormWizard.done()` method, :meth:`~FormWizard.done()` method.
which specifies what should happen when the data for *every* form is submitted
and validated. This method is passed two arguments:
* ``request`` -- an :class:`~django.http.HttpRequest` object .. method:: FormWizard.done
* ``form_list`` -- a list of :mod:`django.forms`
:class:`~django.forms.forms.Form` classes This method specifies what should happen when the data for *every* form is
submitted and validated. This method is passed two arguments:
* ``request`` -- an :class:`~django.http.HttpRequest` object
* ``form_list`` -- a list of :class:`~django.forms.Form` classes
In this simplistic example, rather than perform any database operation, the In this simplistic example, rather than perform any database operation, the
method simply renders a template of the validated data:: method simply renders a template of the validated data::
@ -133,16 +131,16 @@ example::
return HttpResponseRedirect('/page-to-redirect-to-when-done/') return HttpResponseRedirect('/page-to-redirect-to-when-done/')
See the section `Advanced FormWizard methods`_ below to learn about more See the section `Advanced FormWizard methods`_ below to learn about more
:class:`~django.contrib.formtools.wizard.FormWizard` hooks. :class:`FormWizard` hooks.
Creating templates for the forms Creating templates for the forms
================================ ================================
Next, you'll need to create a template that renders the wizard's forms. By Next, you'll need to create a template that renders the wizard's forms. By
default, every form uses a template called :file:`forms/wizard.html`. (You can default, every form uses a template called :file:`forms/wizard.html`. (You can
change this template name by overriding change this template name by overriding :meth:`~FormWizard.get_template()`,
:meth:`~django.contrib.formtools.wizard..get_template()`, which is documented which is documented below. This hook also allows you to use a different
below. This hook also allows you to use a different template for each form.) template for each form.)
This template expects the following context: This template expects the following context:
@ -150,24 +148,20 @@ This template expects the following context:
* ``step0`` -- The current step (zero-based). * ``step0`` -- The current step (zero-based).
* ``step`` -- The current step (one-based). * ``step`` -- The current step (one-based).
* ``step_count`` -- The total number of steps. * ``step_count`` -- The total number of steps.
* ``form`` -- The :class:`~django.forms.forms.Form` instance for the * ``form`` -- The :class:`~django.forms.Form` instance for the current step
current step (either empty or with errors). (either empty or with errors).
* ``previous_fields`` -- A string representing every previous data field, * ``previous_fields`` -- A string representing every previous data field,
plus hashes for completed forms, all in the form of hidden fields. Note plus hashes for completed forms, all in the form of hidden fields. Note
that you'll need to run this through the that you'll need to run this through the :tfilter:`safe` template filter,
:meth:`~django.template.defaultfilters.safe` template filter, to prevent to prevent auto-escaping, because it's raw HTML.
auto-escaping, because it's raw HTML.
It will also be passed any objects in :data:`extra_context`, which is a You can supply extra context to this template in two ways:
dictionary you can specify that contains extra values to add to the context.
You can specify it in two ways:
* Set the :attr:`~django.contrib.formtools.wizard.FormWizard.extra_context` * Set the :attr:`~FormWizard.extra_context` attribute on your
attribute on your :class:`~django.contrib.formtools.wizard.FormWizard` :class:`FormWizard` subclass to a dictionary.
subclass to a dictionary.
* Pass :attr:`~django.contrib.formtools.wizard.FormWizard.extra_context` * Pass a dictionary as a parameter named ``extra_context`` to your wizard's
as extra parameters in the URLconf. URL pattern in your URLconf. See :ref:`hooking-wizard-into-urlconf`.
Here's a full example template: Here's a full example template:
@ -190,12 +184,13 @@ Here's a full example template:
Note that ``previous_fields``, ``step_field`` and ``step0`` are all required Note that ``previous_fields``, ``step_field`` and ``step0`` are all required
for the wizard to work properly. for the wizard to work properly.
.. _hooking-wizard-into-urlconf:
Hooking the wizard into a URLconf Hooking the wizard into a URLconf
================================= =================================
Finally, give your new :class:`~django.contrib.formtools.wizard.FormWizard` Finally, give your new :class:`FormWizard` object a URL in ``urls.py``. The
object a URL in ``urls.py``. The wizard takes a list of your form objects as wizard takes a list of your :class:`~django.forms.Form` objects as arguments::
arguments::
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from mysite.testapp.forms import ContactForm1, ContactForm2, ContactWizard from mysite.testapp.forms import ContactForm1, ContactForm2, ContactWizard
@ -209,19 +204,18 @@ Advanced FormWizard methods
.. class:: FormWizard .. class:: FormWizard
Aside from the :meth:`~django.contrib.formtools.wizard.FormWizard.done()` Aside from the :meth:`~done()` method, :class:`FormWizard` offers a few
method, :class:`~django.contrib.formtools.wizard.FormWizard` offers a few
advanced method hooks that let you customize how your wizard works. 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 Some of these methods take an argument ``step``, which is a zero-based
representing the current step of the wizard. (E.g., the first form is ``0`` and counter representing the current step of the wizard. (E.g., the first form
the second form is ``1``.) is ``0`` and the second form is ``1``.)
.. method:: FormWizard.prefix_for_step .. method:: FormWizard.prefix_for_step
Given the step, returns a :class:`~django.forms.forms.Form` prefix to Given the step, returns a form prefix to use. By default, this simply uses
use. By default, this simply uses the step itself. For more, see the the step itself. For more, see the :ref:`form prefix documentation
:ref:`form prefix documentation <form-prefix>`. <form-prefix>`.
Default implementation:: Default implementation::
@ -237,15 +231,18 @@ Advanced FormWizard methods
def render_hash_failure(self, request, step): def render_hash_failure(self, request, step):
return self.render(self.get_form(step), request, step, return self.render(self.get_form(step), request, step,
context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'}) context={'wizard_error':
'We apologize, but your form has expired. Please'
' continue filling out the form from this page.'})
.. method:: FormWizard.security_hash .. method:: FormWizard.security_hash
Calculates the security hash for the given request object and :class:`~django.forms.forms.Form` instance. Calculates the security hash for the given request object and
:class:`~django.forms.Form` instance.
By default, this uses an MD5 hash of the form data and your By default, this uses an MD5 hash of the form data and your
:setting:`SECRET_KEY` setting. It's rare that somebody would need to override :setting:`SECRET_KEY` setting. It's rare that somebody would need to
this. override this.
Example:: Example::
@ -254,8 +251,8 @@ Advanced FormWizard methods
.. method:: FormWizard.parse_params .. method:: FormWizard.parse_params
A hook for saving state from the request object and ``args`` / ``kwargs`` that A hook for saving state from the request object and ``args`` / ``kwargs``
were captured from the URL by your URLconf. that were captured from the URL by your URLconf.
By default, this does nothing. By default, this does nothing.
@ -275,26 +272,23 @@ Advanced FormWizard methods
def get_template(self, step): def get_template(self, step):
return 'myapp/wizard_%s.html' % step return 'myapp/wizard_%s.html' % step
If :meth:`~FormWizard.get_template` returns a list of strings, then the wizard will use the If :meth:`~FormWizard.get_template` returns a list of strings, then the
template system's :func:`~django.template.loader.select_template()` wizard will use the template system's
function, :func:`~django.template.loader.select_template` function.
:ref:`explained in the template docs <ref-templates-api-the-python-api>`.
This means the system will use the first template that exists on the This means the system will use the first template that exists on the
filesystem. For example:: filesystem. For example::
def get_template(self, step): def get_template(self, step):
return ['myapp/wizard_%s.html' % step, 'myapp/wizard.html'] return ['myapp/wizard_%s.html' % step, 'myapp/wizard.html']
.. _explained in the template docs: ../templates_python/#the-python-api
.. method:: FormWizard.render_template .. method:: FormWizard.render_template
Renders the template for the given step, returning an Renders the template for the given step, returning an
:class:`~django.http.HttpResponse` object. :class:`~django.http.HttpResponse` object.
Override this method if you want to add a custom context, return a different Override this method if you want to add a custom context, return a
MIME type, etc. If you only need to override the template name, use different MIME type, etc. If you only need to override the template name,
:meth:`~FormWizard.get_template` instead. use :meth:`~FormWizard.get_template` instead.
The template will be rendered with the context documented in the The template will be rendered with the context documented in the
"Creating templates for the forms" section above. "Creating templates for the forms" section above.
@ -302,12 +296,12 @@ Advanced FormWizard methods
.. method:: FormWizard.process_step .. method:: FormWizard.process_step
Hook for modifying the wizard's internal state, given a fully validated Hook for modifying the wizard's internal state, given a fully validated
:class:`~django.forms.forms.Form` object. The Form is guaranteed to :class:`~django.forms.Form` object. The Form is guaranteed to have clean,
have clean, valid data. valid data.
This method should *not* modify any of that data. Rather, it might want to set This method should *not* modify any of that data. Rather, it might want to
``self.extra_context`` or dynamically alter ``self.form_list``, based on set ``self.extra_context`` or dynamically alter ``self.form_list``, based
previously submitted forms. on previously submitted forms.
Note that this method is called every time a page is rendered for *all* Note that this method is called every time a page is rendered for *all*
submitted steps. submitted steps.