177
docs/Makefile
Normal file
177
docs/Makefile
Normal file
@@ -0,0 +1,177 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-formtools.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-formtools.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/django-formtools"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-formtools"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
325
docs/conf.py
Normal file
325
docs/conf.py
Normal file
@@ -0,0 +1,325 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# django-formtools documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Oct 6 21:51:30 2014.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings')
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('extensions'))
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig',
|
||||
'sphinx.ext.viewcode', 'settings']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
# templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'django-formtools'
|
||||
copyright = u'2014, Django Software Foundation and individual contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
try:
|
||||
from formtools import __version__
|
||||
# The short X.Y version.
|
||||
version = '.'.join(__version__.split('.')[:2])
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = __version__
|
||||
except ImportError:
|
||||
version = release = 'dev'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = ['_theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
# html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'django-formtoolsdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'django-formtools.tex', u'django-formtools Documentation',
|
||||
u'Django Software Foundation and individual contributors', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'django-formtools', u'django-formtools Documentation',
|
||||
[u'Django Software Foundation and individual contributors'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'django-formtools', u'django-formtools Documentation',
|
||||
u'Django Software Foundation and individual contributors', 'django-formtools', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
# -- Options for Epub output ---------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = u'django-formtools'
|
||||
epub_author = u'Django Software Foundation and individual contributors'
|
||||
epub_publisher = u'Django Software Foundation and individual contributors'
|
||||
epub_copyright = u'2014, Django Software Foundation and individual contributors'
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
#epub_language = ''
|
||||
|
||||
# The scheme of the identifier. Typical schemes are ISBN or URL.
|
||||
#epub_scheme = ''
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#epub_uid = ''
|
||||
|
||||
# A tuple containing the cover image and cover page html template filenames.
|
||||
#epub_cover = ()
|
||||
|
||||
# A sequence of (type, uri, title) tuples for the guide element of content.opf.
|
||||
#epub_guide = ()
|
||||
|
||||
# HTML files that should be inserted before the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_pre_files = []
|
||||
|
||||
# HTML files shat should be inserted after the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_post_files = []
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
#epub_exclude_files = []
|
||||
|
||||
# The depth of the table of contents in toc.ncx.
|
||||
#epub_tocdepth = 3
|
||||
|
||||
# Allow duplicate toc entries.
|
||||
#epub_tocdup = True
|
||||
|
||||
# Fix unsupported image types using the PIL.
|
||||
#epub_fix_images = False
|
||||
|
||||
# Scale large images.
|
||||
#epub_max_image_width = 0
|
||||
|
||||
# If 'no', URL addresses will not be shown.
|
||||
#epub_show_urls = 'inline'
|
||||
|
||||
# If false, no index is generated.
|
||||
#epub_use_index = True
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
'http://docs.python.org/': None,
|
||||
'django': ('http://docs.djangoproject.com/en/dev/',
|
||||
'http://docs.djangoproject.com/en/dev/_objects/'),
|
||||
}
|
||||
0
docs/extensions/__init__.py
Normal file
0
docs/extensions/__init__.py
Normal file
6
docs/extensions/settings.py
Normal file
6
docs/extensions/settings.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def setup(app):
|
||||
app.add_crossref_type(
|
||||
directivename="setting",
|
||||
rolename="setting",
|
||||
indextemplate="pair: %s; setting",
|
||||
)
|
||||
112
docs/index.rst
Normal file
112
docs/index.rst
Normal file
@@ -0,0 +1,112 @@
|
||||
====================
|
||||
The "form tools" app
|
||||
====================
|
||||
|
||||
.. module:: formtools
|
||||
:synopsis: A set of high-level abstractions for Django forms
|
||||
(:mod:`django.forms`)..
|
||||
|
||||
django-formtools is a collection of assorted utilities that are useful for
|
||||
specific form use cases.
|
||||
|
||||
Currently there are two tools: a helper for form previews and a form wizard
|
||||
view.
|
||||
|
||||
.. toctree::
|
||||
|
||||
preview
|
||||
wizard
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
To install django-formtools use your favorite packaging tool, e.g.pip::
|
||||
|
||||
pip install django-formtools
|
||||
|
||||
Or download the source distribution from PyPI_ at
|
||||
https://pypi.python.org/pypi/django-formtools, decompress the file and
|
||||
run ``python setup.py install`` in the unpacked directory.
|
||||
|
||||
Then add ``'formtools'`` to your :setting:`INSTALLED_APPS` setting::
|
||||
|
||||
INSTALLED_APPS = (
|
||||
# ...
|
||||
'formtools',
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
Adding ``'formtools'`` to your ``INSTALLED_APPS`` setting is required
|
||||
for translations and templates to work. Using django-formtools without
|
||||
adding it to your ``INSTALLED_APPS`` setting is not recommended.
|
||||
|
||||
.. _PyPI: https://pypi.python.org/
|
||||
|
||||
Internationalization
|
||||
====================
|
||||
|
||||
Formtools has its own catalog of translations, in the directory
|
||||
``formtools/locale``, and it's not loaded automatically like Django's
|
||||
general catalog in ``django/conf/locale``. If you want formtools's
|
||||
texts to be translated, like the templates, you must include
|
||||
:mod:`formtools` in the :setting:`INSTALLED_APPS` setting, so
|
||||
the internationalization system can find the catalog, as explained in
|
||||
:ref:`django:how-django-discovers-translations`.
|
||||
|
||||
Contributing tools
|
||||
==================
|
||||
|
||||
We'd love to add more of these, so please `create a ticket`_ with
|
||||
any code you'd like to contribute. One thing we ask is that you please use
|
||||
Unicode objects (``u'mystring'``) for strings, rather than setting the encoding
|
||||
in the file. See any of the existing flavors for examples.
|
||||
|
||||
See the `contributing documentation`_ for how to run the tests while working on a
|
||||
local flavor.
|
||||
|
||||
.. _create a ticket: https://github.com/django/django-formtools/issues
|
||||
.. _contributing documentation: https://github.com/django/django-formtools/blob/master/CONTRIBUTING.rst
|
||||
|
||||
Releases
|
||||
========
|
||||
|
||||
Due to django-formtools' history as a former contrib app, the app is
|
||||
required to be working with the actively maintained Django versions. See
|
||||
the documenation about `Django's release process`_ for more information.
|
||||
|
||||
django-formtools releases are not tied to the release cycle of Django.
|
||||
Version numbers follow the appropriate Python standards, e.g. PEPs 386_ and 440_.
|
||||
|
||||
.. _386: http://www.python.org/dev/peps/pep-0386/
|
||||
.. _440: http://www.python.org/dev/peps/pep-0440/
|
||||
.. _`Django's release process`: https://docs.djangoproject.com/en/dev/internals/release-process/
|
||||
|
||||
How to migrate
|
||||
==============
|
||||
|
||||
If you've used the old ``django.contrib.formtools`` package follow these
|
||||
two easy steps to update your code:
|
||||
|
||||
1. Install the third-party ``django-formtools`` package.
|
||||
|
||||
2. Change your app's import statements to reference the new packages.
|
||||
|
||||
For example, change this::
|
||||
|
||||
from django.contrib.formtools.wizard.views import WizardView
|
||||
|
||||
...to this::
|
||||
|
||||
from formtools.wizard.views import WizardView
|
||||
|
||||
The code in the new package is the same (it was copied directly from Django),
|
||||
so you don't have to worry about backwards compatibility in terms of
|
||||
functionality. Only the imports have changed.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
242
docs/make.bat
Normal file
242
docs/make.bat
Normal file
@@ -0,0 +1,242 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. xml to make Docutils-native XML files
|
||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
%SPHINXBUILD% 2> nul
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-formtools.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-formtools.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdf" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdfja" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf-ja
|
||||
cd %BUILDDIR%/..
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "xml" (
|
||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pseudoxml" (
|
||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
120
docs/preview.rst
Normal file
120
docs/preview.rst
Normal file
@@ -0,0 +1,120 @@
|
||||
============
|
||||
Form preview
|
||||
============
|
||||
|
||||
.. module:: formtools.preview
|
||||
:synopsis: Displays an HTML form, forces a preview, then does something
|
||||
with the submission.
|
||||
|
||||
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 :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.
|
||||
|
||||
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 ``'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.
|
||||
|
||||
* Otherwise, determine the full filesystem path to the
|
||||
:file:`django/contrib/formtools/templates` directory, and add that
|
||||
directory to your :setting:`TEMPLATE_DIRS` setting.
|
||||
|
||||
2. Create a :class:`~formtools.preview.FormPreview` subclass that
|
||||
overrides the ``done()`` method::
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from 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 :class:`~django.http.HttpRequest` object and a
|
||||
dictionary of the form data after it has been validated and cleaned.
|
||||
It should return an :class:`~django.http.HttpResponseRedirect` that
|
||||
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::
|
||||
|
||||
from myapp.preview import SomeModelFormPreview
|
||||
from myapp.forms import SomeModelForm
|
||||
from django import forms
|
||||
|
||||
...and add the following line to the appropriate model in your URLconf::
|
||||
|
||||
url(r'^post/$', SomeModelFormPreview(SomeModelForm)),
|
||||
|
||||
where ``SomeModelForm`` is a Form or ModelForm class for the model.
|
||||
|
||||
4. Run the Django server and visit :file:`/post/` in your browser.
|
||||
|
||||
``FormPreview`` classes
|
||||
=======================
|
||||
|
||||
.. class:: FormPreview
|
||||
|
||||
A :class:`~formtools.preview.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()``
|
||||
method. They can live anywhere in your codebase.
|
||||
|
||||
``FormPreview`` templates
|
||||
=========================
|
||||
|
||||
.. attribute:: FormPreview.form_template
|
||||
.. attribute:: FormPreview.preview_template
|
||||
|
||||
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.
|
||||
|
||||
Advanced ``FormPreview`` methods
|
||||
================================
|
||||
|
||||
.. method:: FormPreview.process_preview()
|
||||
|
||||
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.
|
||||
1
docs/requirements.txt
Normal file
1
docs/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
Django
|
||||
761
docs/wizard.rst
Normal file
761
docs/wizard.rst
Normal file
@@ -0,0 +1,761 @@
|
||||
===========
|
||||
Form wizard
|
||||
===========
|
||||
|
||||
.. module:: formtools.wizard.views
|
||||
:synopsis: Splits forms across multiple Web pages.
|
||||
|
||||
Django comes with an optional "form wizard" application that splits
|
||||
:mod:`forms <django.forms>` 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 ``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 :mod:`forms documentation
|
||||
<django.forms>`. 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`` subclass
|
||||
----------------------------------
|
||||
|
||||
.. class:: SessionWizardView
|
||||
.. class:: CookieWizardView
|
||||
|
||||
The next step is to create a :class:`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 :mod:`sessions documentation <django.contrib.sessions>` on
|
||||
how to enable sessions.
|
||||
|
||||
We will use the :class:`SessionWizardView` in all examples but 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, form_dict, **kwargs)
|
||||
|
||||
This method specifies what should happen when the data for *every* form is
|
||||
submitted and validated. This method is passed a list and dictionary 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 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 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/')
|
||||
|
||||
In addition to ``form_list``, the :meth:`~WizardView.done` method
|
||||
is passed a ``form_dict``, which allows you to access the wizard's
|
||||
forms based on their step names. This is especially useful when using
|
||||
:class:`NamedUrlWizardView`, for example::
|
||||
|
||||
def done(self, form_list, form_dict, **kwargs):
|
||||
user = form_dict['user'].save()
|
||||
credit_card = form_dict['credit_card'].save()
|
||||
# ...
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
Previously, the ``form_dict`` argument wasn't passed to the
|
||||
``done`` method.
|
||||
|
||||
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 (:ref:`see the
|
||||
example below <wizard-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.formsets.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" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% 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
|
||||
---------------------------------
|
||||
|
||||
.. method:: WizardView.as_view()
|
||||
|
||||
Finally, we need to specify which forms to use in the wizard, and then
|
||||
deploy the new :class:`WizardView` object at a URL in the ``urls.py``. The
|
||||
wizard's ``as_view()`` method takes a list of your
|
||||
:class:`~django.forms.Form` classes as an argument during instantiation::
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from myapp.forms import ContactForm1, ContactForm2
|
||||
from myapp.views import ContactWizard
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
|
||||
]
|
||||
|
||||
You can also pass the form list as a class attribute named ``form_list``::
|
||||
|
||||
class ContactWizard(WizardView):
|
||||
form_list = [ContactForm1, ContactForm2]
|
||||
|
||||
.. _wizard-template-for-each-form:
|
||||
|
||||
Using a different template for each form
|
||||
----------------------------------------
|
||||
|
||||
As mentioned above, you may specify a different template for each form.
|
||||
Consider an example using a form wizard to implement a multi-step checkout
|
||||
process for an online store. In the first step, the user specifies a billing
|
||||
and shipping address. In the second step, the user chooses payment type. If
|
||||
they chose to pay by credit card, they will enter credit card information in
|
||||
the next step. In the final step, they will confirm the purchase.
|
||||
|
||||
Here's what the view code might look like::
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from formtools.wizard.views import SessionWizardView
|
||||
|
||||
FORMS = [("address", myapp.forms.AddressForm),
|
||||
("paytype", myapp.forms.PaymentChoiceForm),
|
||||
("cc", myapp.forms.CreditCardForm),
|
||||
("confirmation", myapp.forms.OrderForm)]
|
||||
|
||||
TEMPLATES = {"address": "checkout/billingaddress.html",
|
||||
"paytype": "checkout/paymentmethod.html",
|
||||
"cc": "checkout/creditcard.html",
|
||||
"confirmation": "checkout/confirmation.html"}
|
||||
|
||||
def pay_by_credit_card(wizard):
|
||||
"""Return true if user opts to pay by credit card"""
|
||||
# Get cleaned data from payment step
|
||||
cleaned_data = wizard.get_cleaned_data_for_step('paytype') or {'method': 'none'}
|
||||
# Return true if the user selected credit card
|
||||
return cleaned_data['method'] == 'cc'
|
||||
|
||||
|
||||
class OrderWizard(SessionWizardView):
|
||||
def get_template_names(self):
|
||||
return [TEMPLATES[self.steps.current]]
|
||||
|
||||
def done(self, form_list, **kwargs):
|
||||
do_something_with_the_form_data(form_list)
|
||||
return HttpResponseRedirect('/page-to-redirect-to-when-done/')
|
||||
...
|
||||
|
||||
The ``urls.py`` file would contain something like::
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^checkout/$', OrderWizard.as_view(FORMS, condition_dict={'cc': pay_by_credit_card})),
|
||||
]
|
||||
|
||||
The ``condition_dict`` can be passed as attribute for the ``as_view()`
|
||||
method or as a class attribute named ``condition_dict``::
|
||||
|
||||
class OrderWizard(WizardView):
|
||||
condition_dict = {'cc': pay_by_credit_card}
|
||||
|
||||
Note that the ``OrderWizard`` object is initialized with a list of pairs.
|
||||
The first element in the pair is a string that corresponds to the name of the
|
||||
step and the second is the form class.
|
||||
|
||||
In this example, the
|
||||
:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names()`
|
||||
method returns a list containing a single template, which is selected based on
|
||||
the name of the current step.
|
||||
|
||||
.. _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=None, form=None)
|
||||
|
||||
Returns the prefix which will be used when calling the form for the given
|
||||
step. ``step`` contains the step name, ``form`` the form class which will
|
||||
be called with the returned prefix.
|
||||
|
||||
If no ``step`` is given, it will be determined automatically. By default,
|
||||
this simply uses the step itself and the ``form`` parameter is not used.
|
||||
|
||||
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 ``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
|
||||
* ``wizard`` -- a dictionary representation of the wizard instance with the
|
||||
following key/values:
|
||||
|
||||
* ``form`` -- :class:`~django.forms.Form` or
|
||||
:class:`~django.forms.formsets.BaseFormSet` instance for the current step
|
||||
* ``steps`` -- A helper object to access the various steps related data
|
||||
* ``management_form`` -- all the management data for the current step
|
||||
|
||||
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. If you override
|
||||
``get_form``, however, you will need to set ``step`` yourself using
|
||||
``self.steps.current`` as in the example below. 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)
|
||||
|
||||
# determine the step if not given
|
||||
if step is None:
|
||||
step = self.steps.current
|
||||
|
||||
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_goto_step(step, goto_step, **kwargs)
|
||||
|
||||
This method is called when the step should be changed to something else
|
||||
than the next step. By default, this method just stores the requested
|
||||
step ``goto_step`` in the storage and then renders the new step.
|
||||
|
||||
If you want to store the entered data of the current step before rendering
|
||||
the next step, you can overwrite this method.
|
||||
|
||||
.. 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)
|
||||
|
||||
.. method:: WizardView.get_cleaned_data_for_step(step)
|
||||
|
||||
This method 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.
|
||||
|
||||
.. method:: WizardView.get_all_cleaned_data()
|
||||
|
||||
This method returns a merged dictionary of all form steps' ``cleaned_data``
|
||||
dictionaries. If a step contains a ``FormSet``, the key will be prefixed
|
||||
with ``formset-`` and contain a list of the formset's ``cleaned_data``
|
||||
dictionaries. Note that if two or more steps have a field with the same
|
||||
name, the value for that field from the latest step will overwrite the
|
||||
value from any earlier steps.
|
||||
|
||||
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:`~WizardView.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!'}
|
||||
... }
|
||||
>>> # This example is illustrative only and isn't meant to be run in
|
||||
>>> # the shell since it requires an HttpRequest to pass to the view.
|
||||
>>> wiz = ContactWizard.as_view([ContactForm1, ContactForm2], initial_dict=initial)(request)
|
||||
>>> 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``.
|
||||
|
||||
The ``initial_dict`` can also be added as a class attribute named
|
||||
``initial_dict`` to avoid having the initial data in the ``urls.py``.
|
||||
|
||||
.. _wizard-files:
|
||||
|
||||
Handling files
|
||||
==============
|
||||
|
||||
.. attribute:: WizardView.file_storage
|
||||
|
||||
To handle :class:`~django.forms.FileField` within any step form of the wizard,
|
||||
you have to add a ``file_storage`` to your :class:`WizardView` subclass.
|
||||
|
||||
This storage will temporarily store the uploaded files for the wizard. The
|
||||
``file_storage`` attribute should be a
|
||||
:class:`~django.core.files.storage.Storage` subclass.
|
||||
|
||||
Django provides a built-in storage class (see :ref:`the built-in filesystem
|
||||
storage class <builtin-fs-storage>`)::
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
|
||||
class CustomWizardView(WizardView):
|
||||
...
|
||||
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'photos'))
|
||||
|
||||
.. warning::
|
||||
|
||||
Please remember to take care of removing old temporary files, as the
|
||||
:class:`WizardView` will only remove these files if the wizard finishes
|
||||
correctly.
|
||||
|
||||
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 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 url
|
||||
|
||||
from myapp.forms import ContactForm1, ContactForm2
|
||||
from myapp.views import ContactWizard, show_message_form_condition
|
||||
|
||||
contact_forms = [ContactForm1, ContactForm2]
|
||||
|
||||
urlpatterns = [
|
||||
url(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 :mod:`ModelForms <django.forms.models>` 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 model instances for steps
|
||||
based on ``ModelForm`` and querysets for steps based on ``ModelFormSet``.
|
||||
|
||||
Usage of ``NamedUrlWizardView``
|
||||
===============================
|
||||
|
||||
.. class:: NamedUrlWizardView
|
||||
.. class:: NamedUrlSessionWizardView
|
||||
.. class:: NamedUrlCookieWizardView
|
||||
|
||||
``NamedUrlWizardView`` is a :class:`WizardView` subclass which adds named-urls
|
||||
support to the wizard. This allows you to have separate URLs for every step.
|
||||
You can also use the :class:`NamedUrlSessionWizardView` or :class:`NamedUrlCookieWizardView`
|
||||
classes which preselect the backend used for storing information (Django sessions and
|
||||
browser cookies respectively).
|
||||
|
||||
To use the named URLs, you should not only use the :class:`NamedUrlWizardView` instead of
|
||||
:class:`WizardView`, but you will also have to change your ``urls.py``.
|
||||
|
||||
The :meth:`~WizardView.as_view` method takes two additional arguments:
|
||||
|
||||
* a required ``url_name`` -- the name of the url (as provided in the ``urls.py``)
|
||||
* an optional ``done_step_name`` -- the name of the done step, to be used in the URL
|
||||
|
||||
This is an example of a ``urls.py`` for a contact wizard with two steps, step 1 named
|
||||
``contactdata`` and step 2 named ``leavemessage``::
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
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 = [
|
||||
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})
|
||||
Reference in New Issue
Block a user