============
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."

To force a preview of a form submission, all you have to do is write a short
Python class.

Overview
=========

Given a ``django.newforms.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.

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
on the preview page, the form submission will fail the hash-comparison test.

How to use ``FormPreview``
==========================

    1. Point Django at the default FormPreview templates. There are two ways to
       do this:

       * Add ``'django.contrib.formtools'`` to your ``INSTALLED_APPS``
         setting. This will work if your ``TEMPLATE_LOADERS`` setting includes
         the ``app_directories`` template loader (which is the case by
         default). See the `template loader docs`_ for more.

       * Otherwise, determine the full filesystem path to the
         ``django/contrib/formtools/templates`` directory, and add that
         directory to your ``TEMPLATE_DIRS`` setting.

    2. Create a ``FormPreview`` subclass that overrides the ``done()`` method::

           from django.contrib.formtools.preview import FormPreview
           from myapp.models import SomeModel

           class SomeModelFormPreview(FormPreview):

               def done(self, request, cleaned_data):
                   # Do something with the cleaned_data, then redirect
                   # to a "success" page.
                   return HttpResponseRedirect('/form/success')

       This method takes an ``HttpRequest`` object and a dictionary of the form
       data after it has been validated and cleaned. It should return an
       ``HttpResponseRedirect`` that is the end result of the form being
       submitted.

    3. Change your URLconf to point to an instance of your ``FormPreview``
       subclass::

           from myapp.preview import SomeModelFormPreview
           from myapp.models import SomeModel
           from django import newforms as forms

       ...and add the following line to the appropriate model in your URLconf::

           (r'^post/$', SomeModelFormPreview(forms.models.form_for_model(SomeModel))),

       Or, if you already have a Form class defined for the model::

           (r'^post/$', SomeModelFormPreview(SomeModelForm)),

    4. Run the Django server and visit ``/post/`` in your browser.

.. _template loader docs: ../templates_python/#loader-types

``FormPreview`` classes
=======================

A ``FormPreview`` class is a simple Python class that represents the preview
workflow.  ``FormPreview`` classes must subclass
``django.contrib.formtools.preview.FormPreview`` and override the ``done()``
method. They can live anywhere in your codebase.

``FormPreview`` templates
=========================

By default, the form is rendered via the template ``formtools/form.html``, and
the preview page is rendered via the template ``formtools.preview.html``.
These values can be overridden for a particular form preview by setting
``preview_template`` and ``form_template`` attributes on the FormPreview
subclass. See ``django/contrib/formtools/templates`` for the default templates.
