Improve FormPreview docs to encompass more methods. Fix some cosmetic issues. Fixes issue #32.

This commit is contained in:
Jannis Leidel 2014-12-12 21:22:52 +01:00
parent ee8bb9f4f6
commit 659bdfd889
2 changed files with 64 additions and 37 deletions

View File

@ -9,7 +9,8 @@ Form preview
Django comes with an optional "form preview" application that helps automate
the following workflow:
"Display an HTML form, force a preview, then do something with the submission."
"Display an HTML form, force a preview,
then do something with the submission."
To force a preview of a form submission, all you have to do is write a short
Python class.
@ -17,16 +18,18 @@ Python class.
Overview
=========
Given a :class:`django.forms.Form` subclass that you define, this
Given a :class:`~django.forms.Form` subclass that you define, this
application takes care of the following workflow:
1. Displays the form as HTML on a Web page.
2. Validates the form data when it's submitted via POST.
a. If it's valid, displays a preview page.
b. If it's not valid, redisplays the form with error messages.
3. When the "confirmation" form is submitted from the preview page, calls
a hook that you define -- a ``done()`` method that gets passed the valid
data.
a hook that you define -- a :meth:`~FormPreview.done()` method that
gets passed the valid data.
The framework enforces the required preview by passing a shared-secret hash to
the preview page via hidden form fields. If somebody tweaks the form parameters
@ -39,20 +42,23 @@ How to use ``FormPreview``
do this:
* Add ``'formtools'`` to your
:setting:`INSTALLED_APPS` setting. This will work if your
:setting:`TEMPLATE_LOADERS` setting includes the
``app_directories`` template loader (which is the case by
default). See the :ref:`template loader docs <template-loaders>`
for more.
:setting:`INSTALLED_APPS` setting.
This will work if your :setting:`TEMPLATE_LOADERS` setting includes the
``app_directories`` template loader (which is the case by default).
See the :ref:`template loader docs <template-loaders>` for more.
* Otherwise, determine the full filesystem path to the
:file:`django/contrib/formtools/templates` directory, and add that
:file:`formtools/templates` directory, and add that
directory to your :setting:`TEMPLATE_DIRS` setting.
2. Create a :class:`~formtools.preview.FormPreview` subclass that
2. Create a :class:`~FormPreview` subclass that
overrides the ``done()`` method::
from django.http import HttpResponseRedirect
from formtools.preview import FormPreview
from myapp.models import SomeModel
@ -69,12 +75,13 @@ How to use ``FormPreview``
is the end result of the form being submitted.
3. Change your URLconf to point to an instance of your
:class:`~formtools.preview.FormPreview` subclass::
:class:`~FormPreview` subclass::
from myapp.preview import SomeModelFormPreview
from myapp.forms import SomeModelForm
from django import forms
from myapp.forms import SomeModelForm
from myapp.preview import SomeModelFormPreview
...and add the following line to the appropriate model in your URLconf::
url(r'^post/$', SomeModelFormPreview(SomeModelForm)),
@ -88,10 +95,10 @@ How to use ``FormPreview``
.. class:: FormPreview
A :class:`~formtools.preview.FormPreview` class is a simple Python class
A :class:`~FormPreview` class is a simple Python class
that represents the preview workflow.
:class:`~formtools.preview.FormPreview` classes must subclass
``formtools.preview.FormPreview`` and override the ``done()``
:class:`~FormPreview` classes must subclass
``FormPreview`` and override the ``done()``
method. They can live anywhere in your codebase.
``FormPreview`` templates
@ -102,19 +109,30 @@ method. They can live anywhere in your codebase.
By default, the form is rendered via the template :file:`formtools/form.html`,
and the preview page is rendered via the template :file:`formtools/preview.html`.
These values can be overridden for a particular form preview by setting
:attr:`~formtools.preview.FormPreview.preview_template` and
:attr:`~formtools.preview.FormPreview.form_template` attributes on the
FormPreview subclass. See :file:`django/contrib/formtools/templates` for the
default templates.
:attr:`~FormPreview.preview_template` and
:attr:`~FormPreview.form_template` attributes on the
FormPreview subclass. See :file:`formtools/templates` for the default templates.
Advanced ``FormPreview`` methods
================================
Required methods
================
.. method:: FormPreview.process_preview()
.. automethod:: FormPreview.done
Given a validated form, performs any extra processing before displaying the
preview page, and saves any extra data in context.
Optional methods
================
By default, this method is empty. It is called after the form is validated,
but before the context is modified with hash information and rendered.
.. automethod:: FormPreview.get_auto_id
.. automethod:: FormPreview.get_initial
.. automethod:: FormPreview.get_context
.. automethod:: FormPreview.parse_params
.. automethod:: FormPreview.process_preview
.. automethod:: FormPreview.security_hash
.. automethod:: FormPreview.failed_hash

View File

@ -121,16 +121,16 @@ class FormPreview(object):
def parse_params(self, *args, **kwargs):
"""
Given captured args and kwargs from the URLconf, saves something in
self.state and/or raises Http404 if necessary.
self.state and/or raises :class:`~django.http.Http404` if necessary.
For example, this URLconf captures a user_id variable:
For example, this URLconf captures a user_id variable::
(r'^contact/(?P<user_id>\d{1,6})/$', MyFormPreview(MyForm)),
In this case, the kwargs variable in parse_params would be
{'user_id': 32} for a request to '/contact/32/'. You can use that
user_id to make sure it's a valid user and/or save it for later, for
use in done().
``{'user_id': 32}`` for a request to ``'/contact/32/'``. You can use
that ``user_id`` to make sure it's a valid user and/or save it for
later, for use in :meth:`~formtools.preview.FormPreview.done()`.
"""
pass
@ -138,12 +138,17 @@ class FormPreview(object):
"""
Given a validated form, performs any extra processing before displaying
the preview page, and saves any extra data in context.
By default, this method is empty. It is called after the form is
validated, but before the context is modified with hash information
and rendered.
"""
pass
def security_hash(self, request, form):
"""
Calculates the security hash for the given HttpRequest and Form
Calculates the security hash for the given
:class:`~django.http.HttpRequest` and :class:`~django.forms.Form`
instances.
Subclasses may want to take into account request-specific information,
@ -152,15 +157,19 @@ class FormPreview(object):
return form_hmac(form)
def failed_hash(self, request):
"Returns an HttpResponse in the case of an invalid security hash."
"""
Returns an :class:`~django.http.HttpResponse` in the case of
an invalid security hash.
"""
return self.preview_post(request)
# METHODS SUBCLASSES MUST OVERRIDE ########################################
def done(self, request, cleaned_data):
"""
Does something with the cleaned_data and returns an
HttpResponseRedirect.
Does something with the ``cleaned_data`` data and then needs to
return an :class:`~django.http.HttpResponseRedirect`, e.g. to a
success page.
"""
raise NotImplementedError('You must define a done() method on your '
'%s subclass.' % self.__class__.__name__)