Fixed #22796 -- Added a more basic explanations of forms.
Thanks bmispelon, kezabelle, jorgecarleitao, and timgraham for reviews.
This commit is contained in:
parent
dbbcfca476
commit
cd20b5d186
|
@ -376,6 +376,8 @@ You can write code to perform validation for particular form fields (based on
|
||||||
their name) or for the form as a whole (considering combinations of various
|
their name) or for the form as a whole (considering combinations of various
|
||||||
fields). More information about this is in :doc:`/ref/forms/validation`.
|
fields). More information about this is in :doc:`/ref/forms/validation`.
|
||||||
|
|
||||||
|
.. _ref-forms-api-outputting-html:
|
||||||
|
|
||||||
Outputting forms as HTML
|
Outputting forms as HTML
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -492,6 +494,8 @@ it calls its ``as_table()`` method behind the scenes::
|
||||||
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr>
|
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr>
|
||||||
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
||||||
|
|
||||||
|
.. _ref-forms-api-styling-form-rows:
|
||||||
|
|
||||||
Styling required or erroneous form rows
|
Styling required or erroneous form rows
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
à
|
||||||
Aalto
|
Aalto
|
||||||
accessor
|
accessor
|
||||||
Aceh
|
Aceh
|
||||||
|
@ -153,6 +154,7 @@ dirmod
|
||||||
distro
|
distro
|
||||||
divisibleby
|
divisibleby
|
||||||
django
|
django
|
||||||
|
Django's
|
||||||
djangojs
|
djangojs
|
||||||
djangonaut
|
djangonaut
|
||||||
djangoproject
|
djangoproject
|
||||||
|
|
|
@ -56,7 +56,7 @@ Using initial data with a formset
|
||||||
Initial data is what drives the main usability of a formset. As shown above
|
Initial data is what drives the main usability of a formset. As shown above
|
||||||
you can define the number of extra forms. What this means is that you are
|
you can define the number of extra forms. What this means is that you are
|
||||||
telling the formset how many additional forms to show in addition to the
|
telling the formset how many additional forms to show in addition to the
|
||||||
number of forms it generates from the initial data. Lets take a look at an
|
number of forms it generates from the initial data. Let's take a look at an
|
||||||
example::
|
example::
|
||||||
|
|
||||||
>>> import datetime
|
>>> import datetime
|
||||||
|
|
|
@ -2,128 +2,372 @@
|
||||||
Working with forms
|
Working with forms
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
.. currentmodule:: django.forms
|
||||||
|
|
||||||
.. admonition:: About this document
|
.. admonition:: About this document
|
||||||
|
|
||||||
This document provides an introduction to Django's form handling features.
|
This document provides an introduction to the basics of web forms and how
|
||||||
For a more detailed look at specific areas of the forms API, see
|
they are handled in Django. For a more detailed look at specific areas of
|
||||||
:doc:`/ref/forms/api`, :doc:`/ref/forms/fields`, and
|
the forms API, see :doc:`/ref/forms/api`, :doc:`/ref/forms/fields`, and
|
||||||
:doc:`/ref/forms/validation`.
|
:doc:`/ref/forms/validation`.
|
||||||
|
|
||||||
.. highlightlang:: html+django
|
Unless you're planning to build websites and applications that do nothing but
|
||||||
|
publish content, and don't accept input from your visitors, you're going to
|
||||||
|
need to understand and use forms.
|
||||||
|
|
||||||
``django.forms`` is Django's form-handling library.
|
Django provides a range of tools and libraries to help you build forms to
|
||||||
|
accept input from site visitors, and process and respond to the input.
|
||||||
|
|
||||||
While it is possible to process form submissions just using Django's
|
HTML forms
|
||||||
:class:`~django.http.HttpRequest` class, using the form library takes care of a
|
==========
|
||||||
number of common form-related tasks. Using it, you can:
|
|
||||||
|
|
||||||
1. Display an HTML form with automatically generated form widgets.
|
In HTML, a form is a collection of elements inside ``<form>...</form>`` that
|
||||||
2. Check submitted data against a set of validation rules.
|
allow a visitor to do things like enter text, select options, manipulate
|
||||||
3. Redisplay a form in the case of validation errors.
|
objects or controls, and so on, and then send that information back to the
|
||||||
4. Convert submitted form data to the relevant Python data types.
|
server.
|
||||||
|
|
||||||
Overview
|
Some of these form interface elements - text input or checkboxes - are fairly
|
||||||
========
|
simple and built-in to HTML itself. Others are much more complex; an interface
|
||||||
|
that pops up a date picker or allows you to move a slider or manipulate
|
||||||
|
controls will typically use JavaScript and CSS as well as HTML form ``<input>``
|
||||||
|
elements to achieve these effects.
|
||||||
|
|
||||||
The library deals with these concepts:
|
As well as its ``<input>`` elements, a form must specify two things:
|
||||||
|
|
||||||
.. glossary::
|
* *where*: the URL to which the data corresponding to the user's input should
|
||||||
|
be returned
|
||||||
|
|
||||||
Widget
|
* *how*: the HTTP method the data should be returned by
|
||||||
A class that corresponds to an HTML form widget, e.g.
|
|
||||||
``<input type="text">`` or ``<textarea>``. This handles rendering of the
|
|
||||||
widget as HTML.
|
|
||||||
|
|
||||||
Field
|
As an example, the standard Django login form contains several ``<input>``
|
||||||
A class that is responsible for doing validation, e.g.
|
elements: one of ``type="text"`` for the username, one of ``type="password"``
|
||||||
an ``EmailField`` that makes sure its data is a valid email address.
|
for the password, and one of one of ``type="submit"`` for the "Log in" button.
|
||||||
|
It also contains some hidden text fields that the user doesn't see, that Django
|
||||||
|
uses to determine what to do next.
|
||||||
|
|
||||||
Form
|
It also tells the browser that the form data should be sent to the URL
|
||||||
A collection of fields that knows how to validate itself and
|
specified in the ``<form>``’s ``action`` attribute - ``/admin/`` - and that it
|
||||||
display itself as HTML.
|
should be sent using the HTTP mechanism specified by the ``method`` attribute -
|
||||||
|
``post``.
|
||||||
|
|
||||||
Form Assets (the ``Media`` class)
|
When the ``<input type="submit" value="Log in">`` element is triggered, the
|
||||||
The CSS and JavaScript resources that are required to render a form.
|
data are returned to ``/admin/``.
|
||||||
|
|
||||||
The library is decoupled from the other Django components, such as the database
|
``GET`` and ``POST``
|
||||||
layer, views and templates. It relies only on Django settings, a couple of
|
--------------------
|
||||||
``django.utils`` helper functions and Django's internationalization hooks (but
|
|
||||||
you're not required to be using internationalization features to use this
|
|
||||||
library).
|
|
||||||
|
|
||||||
Form objects
|
``GET`` and ``POST`` are the only HTTP methods to use when dealing with forms.
|
||||||
============
|
|
||||||
|
|
||||||
A Form object encapsulates a sequence of form fields and a collection of
|
Django's login form is returned using the ``POST`` method, in which the browser
|
||||||
validation rules that must be fulfilled in order for the form to be accepted.
|
bundles up the form data, encodes them for transmission, sends them back to
|
||||||
Form classes are created as subclasses of ``django.forms.Form`` and
|
the server, and then receives its response.
|
||||||
make use of a declarative style that you'll be familiar with if you've used
|
|
||||||
Django's database models.
|
|
||||||
|
|
||||||
For example, consider a form used to implement "contact me" functionality on a
|
``GET`` by contrast bundles the submitted data into a string, and uses this to
|
||||||
personal Web site:
|
compose a URL. The URL contains the address where the data must be sent, as
|
||||||
|
well as the data keys and values. You can see this in action if you do a search
|
||||||
|
in the Django documentation, which will produce a URL of the form
|
||||||
|
``https://docs.djangoproject.com/search/?q=forms&release=1``.
|
||||||
|
|
||||||
|
``GET`` and ``POST`` are typically used for different purposes.
|
||||||
|
|
||||||
|
Any request that could be used to change the state of the system - for example,
|
||||||
|
a request that makes changes in the database - should use ``POST``. ``GET``
|
||||||
|
should be used only for requests that do not affect the state of the system.
|
||||||
|
|
||||||
|
``GET`` would also be unsuitable for a password form, because the password
|
||||||
|
would appear in the URL, and thus also in browser history and server logs,
|
||||||
|
all in plaintext. Neither would it be suitable for large quantities of data,
|
||||||
|
or for binary data, such as an image. A web application that uses ``GET``
|
||||||
|
requests for admin forms is a security risk: it can be easy for an attacker to
|
||||||
|
mimic a form's request to gain access to sensitive parts of the system.
|
||||||
|
``POST``, coupled with other protections like Django's:doc:`CSRF protection
|
||||||
|
</ref/contrib/csrf/>` offers more control over access.
|
||||||
|
|
||||||
|
On the other hand, ``GET`` is suitable for things like a web search form,
|
||||||
|
because the URLs that represent a ``GET`` request can easily be bookmarked,
|
||||||
|
shared, or resubmitted.
|
||||||
|
|
||||||
|
Django's role in forms
|
||||||
|
======================
|
||||||
|
|
||||||
|
Handling forms is a complex business. Consider Django's admin, where numerous
|
||||||
|
items of data of various different types may need to be prepared for display in
|
||||||
|
a form, rendered as HTML, edited using a convenient interface, returned to the
|
||||||
|
server, validated and cleaned up, and then saved or passed on for further
|
||||||
|
processing.
|
||||||
|
|
||||||
|
Django's form functionality can simplify and automate vast portions of this
|
||||||
|
work, and also do it more safely and securely than most programmers would be
|
||||||
|
able to do in code they wrote themselves.
|
||||||
|
|
||||||
|
Django handles three distinct parts of the work involved in forms.
|
||||||
|
|
||||||
|
* preparing and restructuring data ready for rendering
|
||||||
|
* creating HTML forms for the data
|
||||||
|
* receiving and processing submitted forms and data from the client
|
||||||
|
|
||||||
|
It's *possible* to write code that does all of this manually, but Django can
|
||||||
|
take care of it all for you.
|
||||||
|
|
||||||
|
Forms in Django
|
||||||
|
===============
|
||||||
|
|
||||||
|
We've described HTML forms briefly, but an HTML ``<form>`` is just one part of
|
||||||
|
the machinery required.
|
||||||
|
|
||||||
|
In the context of a web application, 'form' might refer to that HTML
|
||||||
|
``<form>``, or to the Django :class:`Form` that produces it, or to the
|
||||||
|
structured data returned when it is submitted, or to the end-to-end working
|
||||||
|
collection of these parts.
|
||||||
|
|
||||||
|
The Django :class:`Form` class
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
At the heart of this system of components is Django's :class:`Form` class. In
|
||||||
|
much the same way that a Django model describes the logical structure of an
|
||||||
|
object, its behavior, and the way its parts are represented to us, a
|
||||||
|
:class:`Form` class describes a form and determines how it works and appears.
|
||||||
|
|
||||||
|
In a similar way that a model class's fields map to database fields, a form
|
||||||
|
class's fields map to HTML form ``<input>`` elements. (A :class:`ModelForm`
|
||||||
|
maps a model class's fields to HTML form ``<input>`` elements via a
|
||||||
|
:class:`Form`; this is what the Django admin is based upon.)
|
||||||
|
|
||||||
|
A form's fields are themselves classes; they manage form data and perform
|
||||||
|
validation when a form is submitted. A ``DateField`` and a ``FileField`` handle
|
||||||
|
very different kinds of data and have to do different things with them.
|
||||||
|
|
||||||
|
A form field is represented to a user in the browser as a HTML "widget" - a
|
||||||
|
piece of user interface machinery. Each field type has an appropriate default
|
||||||
|
:doc:`Widget class </ref/forms/widgets/>`, but these can be overridden as
|
||||||
|
required.
|
||||||
|
|
||||||
|
Instantiating, processing, and rendering forms
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
When rendering an object in Django we generally:
|
||||||
|
|
||||||
|
1. get hold of it in the view (fetch it from the database, for example)
|
||||||
|
2. pass it to the template context
|
||||||
|
3. expand it to HTML markup using template variables
|
||||||
|
|
||||||
|
Rendering a form in a template involves nearly the same work as rendering any
|
||||||
|
other kind of object, but there are some key differences.
|
||||||
|
|
||||||
|
In the case of a model instance that contained no data it would rarely if ever
|
||||||
|
be useful to do anything with one in a template. On the other hand, it makes
|
||||||
|
perfect sense to render an unpopulated form - that's what we do when we want
|
||||||
|
the user to populate it.
|
||||||
|
|
||||||
|
So when we handle a model instance in a view we typically retrieve it from the
|
||||||
|
database; when we're dealing with a form we typically instantiate it in the
|
||||||
|
view.
|
||||||
|
|
||||||
|
When we instantiate a form, we can opt to leave it empty or pre-populate it, for
|
||||||
|
example with:
|
||||||
|
|
||||||
|
* data from a saved model instance (as in the case of admin forms for editing)
|
||||||
|
* data that we have collated from other sources
|
||||||
|
* data received from a previous HTML form submission
|
||||||
|
|
||||||
|
The last of these cases is the most interesting, because it's what makes it
|
||||||
|
possible for users not just to read a website, but to send information back to
|
||||||
|
it too.
|
||||||
|
|
||||||
|
Building a form
|
||||||
|
===============
|
||||||
|
|
||||||
|
The work that needs to done
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Suppose you want to create a simple form on your website, to obtain the user's
|
||||||
|
name. You'd need something like this in your template:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
|
<form action="/your-name/" method="post">
|
||||||
|
<label for="your_name">Your name: </label>
|
||||||
|
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
|
||||||
|
<input type="submit" value="OK">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
This tells the browser to return the form data to the URL ``/your-name/``, using
|
||||||
|
the ``POST`` method. It will display a text field, labeled "Your name:", and a
|
||||||
|
button marked "OK". If the template context contains a ``current_name``
|
||||||
|
variable, that will be used to pre-fill the ``your_name`` field.
|
||||||
|
|
||||||
|
You'll need a view that renders the template containing the HTML form, and
|
||||||
|
that can supply the ``current_name`` field as appropriate.
|
||||||
|
|
||||||
|
When the form is submitted, the ``POST`` request sent to the server will contain
|
||||||
|
the form data.
|
||||||
|
|
||||||
|
Now you'll also need a view corresponding to that ``/your-name/`` URL which will
|
||||||
|
find the appropriate key/value pairs in the request and process them.
|
||||||
|
|
||||||
|
This is a very simple form. In practice, a form might contain dozens or
|
||||||
|
hundreds of fields, many of which might need to be pre-populated, and we might
|
||||||
|
expect the user to work through the edit-submit cycle several times before
|
||||||
|
concluding the operation.
|
||||||
|
|
||||||
|
We might require some validation to occur in the browser, even before the form
|
||||||
|
is submitted; we might want to use much more complex fields, that allow the
|
||||||
|
user to do things like pick dates from a calendar; and so on.
|
||||||
|
|
||||||
|
At this point it's much easier to get Django to do most of this work for us.
|
||||||
|
|
||||||
|
Building a form in Django
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The :class:`Form` class
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
We already know what we want our HTML form to look like. Our starting point for
|
||||||
|
it in Django is this:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
class ContactForm(forms.Form):
|
class NameForm(forms.Form):
|
||||||
subject = forms.CharField(max_length=100)
|
your_name = forms.CharField(label='Your name', max_length=100)
|
||||||
message = forms.CharField()
|
|
||||||
sender = forms.EmailField()
|
|
||||||
cc_myself = forms.BooleanField(required=False)
|
|
||||||
|
|
||||||
A form is composed of ``Field`` objects. In this case, our form has four
|
This defines a :class:`Form` class with a single field (``your_name``). We've
|
||||||
fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. ``CharField``,
|
applied a human-friendly label to the field, that will appear in the
|
||||||
``EmailField`` and ``BooleanField`` are just three of the available field types;
|
``<label>`` when it's rendered (although in this case, the :attr:`~Field.label`
|
||||||
a full list can be found in :doc:`/ref/forms/fields`.
|
we specified is actually the same one that would be generated automatically if
|
||||||
|
we had omitted it).
|
||||||
|
|
||||||
If your form is going to be used to directly add or edit a Django model, you can
|
The field's maximum allowable length is defined by
|
||||||
use a :doc:`ModelForm </topics/forms/modelforms>` to avoid duplicating your model
|
:attr:`~CharField.max_length`. This does two things. It puts a
|
||||||
description.
|
``maxlength="100"`` on the HTML ``<input>`` (so the browser should prevent the
|
||||||
|
user entering more than that many characters in the first place). It also means
|
||||||
|
that when Django receives the form back from the browser, it will validate the
|
||||||
|
length of the data.
|
||||||
|
|
||||||
|
A :class:`Form` instance has an :meth:`~Form.is_valid()` method, which runs
|
||||||
|
validation routines for all its fields. When this method is called, if all
|
||||||
|
fields contain valid data, it will:
|
||||||
|
|
||||||
|
* return ``True``
|
||||||
|
* place the form's data in its :attr:`~Form.cleaned_data` attribute.
|
||||||
|
|
||||||
|
The whole form, when rendered for the first time, will look like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
|
<label for="your_name">Your name: </label>
|
||||||
|
<input id="your_name" type="text" name="your_name" maxlength="100">
|
||||||
|
|
||||||
|
Note that it **does not** include the ``<form>`` tags, or a submit button.
|
||||||
|
We'll have to provide those ourselves in the template.
|
||||||
|
|
||||||
.. _using-a-form-in-a-view:
|
.. _using-a-form-in-a-view:
|
||||||
|
|
||||||
Using a form in a view
|
The view
|
||||||
----------------------
|
^^^^^^^^
|
||||||
|
|
||||||
The standard pattern for processing a form in a view looks like this:
|
Form data sent back to a Django website are processed by a view, generally the
|
||||||
|
same view that published the form. This allows us to reuse some of the same
|
||||||
|
logic.
|
||||||
|
|
||||||
|
To handle the form we need to instantiate it in the view for the URL where we
|
||||||
|
want it to be published:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
|
||||||
def contact(request):
|
def get_name(request):
|
||||||
if request.method == 'POST': # If the form has been submitted...
|
# if this is a POST request we need to process the form data
|
||||||
# ContactForm was defined in the previous section
|
if request.method == 'POST':
|
||||||
form = ContactForm(request.POST) # A form bound to the POST data
|
# create a form instance and populate it with data from the request:
|
||||||
if form.is_valid(): # All validation rules pass
|
form = NameForm(request.POST)
|
||||||
# Process the data in form.cleaned_data
|
# check whether it's valid:
|
||||||
# ...
|
if form.is_valid():
|
||||||
return HttpResponseRedirect('/thanks/') # Redirect after POST
|
# process the data in form.cleaned_data as required
|
||||||
else:
|
# ...
|
||||||
form = ContactForm() # An unbound form
|
# redirect to a new URL:
|
||||||
|
return HttpResponseRedirect('/thanks/')
|
||||||
|
|
||||||
return render(request, 'contact.html', {
|
# if a GET (or any other method) we'll create a blank form
|
||||||
'form': form,
|
else:
|
||||||
})
|
form = NameForm()
|
||||||
|
|
||||||
|
return render(request, 'name.html', {'form': form})
|
||||||
|
|
||||||
There are three possible code paths here:
|
If we arrive at this view with a ``GET`` request, it will create an empty form
|
||||||
|
instance and place it in the template context to be rendered. This is what we
|
||||||
|
can expect to happen the first time we visit the URL.
|
||||||
|
|
||||||
+------------------+---------------+-----------------------------------------+
|
If the form is submitted using a ``POST`` request, the view will once again
|
||||||
| Form submitted? | Data? | What occurs |
|
create a form instance and populate it with data from the request: ``form =
|
||||||
+==================+===============+=========================================+
|
NameForm(request.POST)`` (this is called "binding data to the form" - it is now
|
||||||
| Not submitted | None yet | Template gets passed unbound instance |
|
a *bound* form).
|
||||||
| | | of ContactForm. |
|
|
||||||
+------------------+---------------+-----------------------------------------+
|
We call the form's ``is_valid()`` method; if it's not ``True``, we go back to
|
||||||
| Submitted | Invalid data | Template gets passed bound instance |
|
the template with the form. This time the form is no longer empty (*unbound*)
|
||||||
| | | of ContactForm. |
|
so the HTML form will be populated with the data previously submitted, where it
|
||||||
+------------------+---------------+-----------------------------------------+
|
can be edited and corrected as required.
|
||||||
| Submitted | Valid data | Valid data is processed. Redirect to a |
|
|
||||||
| | | "thanks" page. |
|
If ``is_valid()`` is ``True``, we'll now be able to find all the validated form
|
||||||
+------------------+---------------+-----------------------------------------+
|
data in its ``cleaned_data`` attribute. We can use these data to update the
|
||||||
|
database or do other processing before sending an HTTP redirect to the browser
|
||||||
|
telling it where to go next.
|
||||||
|
|
||||||
|
.. _topics-forms-index-basic-form-template:
|
||||||
|
|
||||||
|
The template
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
We don't need to do much in our ``name.html`` template. The simplest example
|
||||||
|
is:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
|
<form action="/your-name/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
All the form's fields and their attributes will be unpacked into HTML markup
|
||||||
|
from that ``{{ form }}`` by Django's template language.
|
||||||
|
|
||||||
|
.. admonition:: Forms and Cross Site Request Forgery protection
|
||||||
|
|
||||||
|
Django ships with an easy-to-use :doc:`protection against Cross Site Request
|
||||||
|
Forgeries </ref/contrib/csrf>`. When submitting a form via ``POST`` with
|
||||||
|
CSRF protection enabled you must use the :ttag:`csrf_token` template tag
|
||||||
|
as in the preceding example. However, since CSRF protection is not
|
||||||
|
directly tied to forms in templates, this tag is omitted from the
|
||||||
|
following examples in this document.
|
||||||
|
|
||||||
|
We now have a working web form, described by a Django :class:`Form`, processed
|
||||||
|
by a view, and rendered as an HTML ``<form>``.
|
||||||
|
|
||||||
|
That's all you need to get started, but the forms framework puts a lot more at
|
||||||
|
your fingertips. Once you understand the basics of the process described above,
|
||||||
|
you should be aware of what else is readily available in the forms system
|
||||||
|
and know a little bit about some of the underlying machinery.
|
||||||
|
|
||||||
|
More about Django :class:`Form` classes
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
All form classes are created as subclasses of ``django.forms.Form``, including
|
||||||
|
the :doc:`ModelForm </topics/forms/modelforms>` you encounter in Django's
|
||||||
|
admin.
|
||||||
|
|
||||||
|
.. admonition:: Models and Forms
|
||||||
|
|
||||||
|
In fact if your form is going to be used to directly add or edit a Django
|
||||||
|
model, a :doc:`ModelForm </topics/forms/modelforms>` can save you a great
|
||||||
|
deal of time, effort, and code, because it will build a form, along with the
|
||||||
|
appropriate fields and their attributes, from a ``Model`` class.
|
||||||
|
|
||||||
|
Bound and unbound form instances
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
The distinction between :ref:`ref-forms-api-bound-unbound` is important:
|
The distinction between :ref:`ref-forms-api-bound-unbound` is important:
|
||||||
|
|
||||||
|
@ -134,37 +378,67 @@ The distinction between :ref:`ref-forms-api-bound-unbound` is important:
|
||||||
is valid. If an invalid bound form is rendered, it can include inline error
|
is valid. If an invalid bound form is rendered, it can include inline error
|
||||||
messages telling the user what data to correct.
|
messages telling the user what data to correct.
|
||||||
|
|
||||||
Handling file uploads with a form
|
The form's ``is_bound()`` method will tell you whether a form has data bound to
|
||||||
---------------------------------
|
it or not.
|
||||||
|
|
||||||
To see how to handle file uploads with your form, see
|
More on fields
|
||||||
:ref:`binding-uploaded-files`.
|
--------------
|
||||||
|
|
||||||
Processing the data from a form
|
Consider a rather more useful form than our minimal example above, that
|
||||||
-------------------------------
|
we could use to implement "contact me" functionality on a personal Web site:
|
||||||
|
|
||||||
Once ``is_valid()`` returns ``True``, the successfully validated form data
|
.. code-block:: python
|
||||||
will be in the ``form.cleaned_data`` dictionary. This data will have been
|
|
||||||
converted nicely into Python types for you.
|
from django import forms
|
||||||
|
|
||||||
|
class ContactForm(forms.Form):
|
||||||
|
subject = forms.CharField(max_length=100)
|
||||||
|
message = forms.CharField(widget=forms.Textarea)
|
||||||
|
sender = forms.EmailField()
|
||||||
|
cc_myself = forms.BooleanField(required=False)
|
||||||
|
|
||||||
|
Our earlier form used a single field, ``your_name``, a ``CharField``. In this
|
||||||
|
case, our form has four fields: ``subject``, ``message``, ``sender`` and
|
||||||
|
``cc_myself``. :class:`CharField`, :class:`EmailField` and
|
||||||
|
:class:`BooleanField` are just three of the available field types; a full list
|
||||||
|
can be found in :doc:`/ref/forms/fields`.
|
||||||
|
|
||||||
|
Widgets
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
Each form field has a corresponding :doc:`Widget class </ref/forms/widgets/>`,
|
||||||
|
which in turn corresponds to an HTML form widget such as ``<input
|
||||||
|
type="text">``.
|
||||||
|
|
||||||
|
In most cases, the field will have a sensible default widget. For example, by
|
||||||
|
default, a ``CharField`` will have a :class:`TextInput` widget, that produces an
|
||||||
|
``<input type="text">`` in the HTML. If you needed ``<input type="textarea">``
|
||||||
|
instead, you'd specify the appropriate widget when defining your form field,
|
||||||
|
as we have done for the ``message`` field.
|
||||||
|
|
||||||
|
Field data
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
Whatever the data submitted with a form, once it has been successfully
|
||||||
|
validated by calling ``is_valid()`` (and ``is_valid()`` has returned ``True``),
|
||||||
|
the validated form data will be in the ``form.cleaned_data`` dictionary. This
|
||||||
|
data will have been converted nicely into Python types for you.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
You can still access the unvalidated data directly from ``request.POST`` at
|
You can still access the unvalidated data directly from ``request.POST`` at
|
||||||
this point, but the validated data is better.
|
this point, but the validated data is better.
|
||||||
|
|
||||||
In the above example, ``cc_myself`` will be a boolean value. Likewise, fields
|
In the contact form example above, ``cc_myself`` will be a boolean value.
|
||||||
such as ``IntegerField`` and ``FloatField`` convert values to a Python int and
|
Likewise, fields such as :class:`IntegerField` and :class:`FloatField` convert
|
||||||
float respectively.
|
values to a Python ``int`` and ``float`` respectively.
|
||||||
|
|
||||||
Read-only fields are not available in ``form.cleaned_data`` (and setting
|
Here's how the form data could be processed in the view that handles this form:
|
||||||
a value in a custom ``clean()`` method won't have any effect). These
|
|
||||||
fields are displayed as text rather than as input elements, and thus are not
|
|
||||||
posted back to the server.
|
|
||||||
|
|
||||||
Extending the earlier example, here's how the form data could be processed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
subject = form.cleaned_data['subject']
|
subject = form.cleaned_data['subject']
|
||||||
message = form.cleaned_data['message']
|
message = form.cleaned_data['message']
|
||||||
|
@ -175,50 +449,51 @@ Extending the earlier example, here's how the form data could be processed:
|
||||||
if cc_myself:
|
if cc_myself:
|
||||||
recipients.append(sender)
|
recipients.append(sender)
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
send_mail(subject, message, sender, recipients)
|
send_mail(subject, message, sender, recipients)
|
||||||
return HttpResponseRedirect('/thanks/') # Redirect after POST
|
return HttpResponseRedirect('/thanks/')
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
|
|
||||||
For more on sending email from Django, see :doc:`/topics/email`.
|
For more on sending email from Django, see :doc:`/topics/email`.
|
||||||
|
|
||||||
Displaying a form using a template
|
Some field types need some extra handling. For example, files that are uploaded
|
||||||
----------------------------------
|
using a form need to be handled differently (they can be retrieved from
|
||||||
|
``request.FILES``, rather than ``request.POST``). For details of how to handle
|
||||||
|
file uploads with your form, see :ref:`binding-uploaded-files`.
|
||||||
|
|
||||||
Forms are designed to work with the Django template language. In the above
|
Working with form templates
|
||||||
example, we passed our ``ContactForm`` instance to the template using the
|
===========================
|
||||||
context variable ``form``. Here's a simple example template::
|
|
||||||
|
|
||||||
<form action="/contact/" method="post">{% csrf_token %}
|
All you need to do to get your form into a template is to place the form
|
||||||
{{ form.as_p }}
|
instance into the template context. So if your form is called ``form`` in the
|
||||||
<input type="submit" value="Submit" />
|
context, ``{{ form }}`` will render its ``<label>`` and ``<input>`` elements
|
||||||
</form>
|
appropriately.
|
||||||
|
|
||||||
The form only outputs its own fields; it is up to you to provide the surrounding
|
Form rendering options
|
||||||
``<form>`` tags and the submit button.
|
----------------------
|
||||||
|
|
||||||
If your form includes uploaded files, be sure to include
|
.. admonition:: Additional form template furniture
|
||||||
``enctype="multipart/form-data"`` in the ``form`` element. If you wish to write
|
|
||||||
a generic template that will work whether or not the form has files, you can
|
|
||||||
use the :meth:`~django.forms.Form.is_multipart` attribute on the form::
|
|
||||||
|
|
||||||
<form action="/contact/" method="post"
|
Don't forget that a form's output does *not* include the surrounding
|
||||||
{% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
|
``<form>`` tags, or the form's ``submit`` control. You will have to provide
|
||||||
|
these yourself.
|
||||||
|
|
||||||
.. admonition:: Forms and Cross Site Request Forgery protection
|
There are other output options though for the ``<label>``/``<input>`` pairs:
|
||||||
|
|
||||||
Django ships with an easy-to-use :doc:`protection against Cross Site Request
|
* ``{{ form.as_table }}`` will render them as table cells wrapped in ``<tr>``
|
||||||
Forgeries </ref/contrib/csrf>`. When submitting a form via POST with
|
tags
|
||||||
CSRF protection enabled you must use the :ttag:`csrf_token` template tag
|
|
||||||
as in the preceding example. However, since CSRF protection is not
|
|
||||||
directly tied to forms in templates, this tag is omitted from the
|
|
||||||
following examples in this document.
|
|
||||||
|
|
||||||
``form.as_p`` will output the form with each form field and accompanying label
|
* ``{{ form.as_p }}`` will render them wrapped in ``<p>`` tags
|
||||||
wrapped in a paragraph. Here's the output for our example template::
|
|
||||||
|
* ``{{ form.as_ul }}`` will render them wrapped in ``<li>`` tags
|
||||||
|
|
||||||
|
Note that you'll have to provide the surrounding ``<table>`` or ``<ul>``
|
||||||
|
elements yourself.
|
||||||
|
|
||||||
|
Here's the output of ``{{ form.as_p }}`` for our ``ContactForm`` instance:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<form action="/contact/" method="post">
|
|
||||||
<p><label for="id_subject">Subject:</label>
|
<p><label for="id_subject">Subject:</label>
|
||||||
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
|
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
|
||||||
<p><label for="id_message">Message:</label>
|
<p><label for="id_message">Message:</label>
|
||||||
|
@ -227,8 +502,6 @@ wrapped in a paragraph. Here's the output for our example template::
|
||||||
<input type="email" name="sender" id="id_sender" /></p>
|
<input type="email" name="sender" id="id_sender" /></p>
|
||||||
<p><label for="id_cc_myself">Cc myself:</label>
|
<p><label for="id_cc_myself">Cc myself:</label>
|
||||||
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
|
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
|
||||||
<input type="submit" value="Submit" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
Note that each form field has an ID attribute set to ``id_<field-name>``, which
|
Note that each form field has an ID attribute set to ``id_<field-name>``, which
|
||||||
is referenced by the accompanying label tag. This is important for ensuring
|
is referenced by the accompanying label tag. This is important for ensuring
|
||||||
|
@ -236,45 +509,53 @@ forms are accessible to assistive technology such as screen reader software. You
|
||||||
can also :ref:`customize the way in which labels and ids are generated
|
can also :ref:`customize the way in which labels and ids are generated
|
||||||
<ref-forms-api-configuring-label>`.
|
<ref-forms-api-configuring-label>`.
|
||||||
|
|
||||||
You can also use ``form.as_table`` to output table rows (you'll need to provide
|
See :ref:`ref-forms-api-outputting-html` for more on this.
|
||||||
your own ``<table>`` tags) and ``form.as_ul`` to output list items.
|
|
||||||
|
|
||||||
Customizing the form template
|
Rendering fields manually
|
||||||
-----------------------------
|
-------------------------
|
||||||
|
|
||||||
If the default generated HTML is not to your taste, you can completely customize
|
We don't have to let Django unpack the form's fields; we can do it manually if
|
||||||
the way a form is presented using the Django template language. Extending the
|
we like (allowing us to reorder the fields, for example). Each field is
|
||||||
above example::
|
available as an attribute of the form using ``{{ form.name_of_field }}``, and
|
||||||
|
in a Django template, will be rendered appropriately. For example:
|
||||||
|
|
||||||
<form action="/contact/" method="post">
|
.. code-block:: html+django
|
||||||
{{ form.non_field_errors }}
|
|
||||||
<div class="fieldWrapper">
|
|
||||||
{{ form.subject.errors }}
|
|
||||||
<label for="id_subject">Email subject:</label>
|
|
||||||
{{ form.subject }}
|
|
||||||
</div>
|
|
||||||
<div class="fieldWrapper">
|
|
||||||
{{ form.message.errors }}
|
|
||||||
<label for="id_message">Your message:</label>
|
|
||||||
{{ form.message }}
|
|
||||||
</div>
|
|
||||||
<div class="fieldWrapper">
|
|
||||||
{{ form.sender.errors }}
|
|
||||||
<label for="id_sender">Your email address:</label>
|
|
||||||
{{ form.sender }}
|
|
||||||
</div>
|
|
||||||
<div class="fieldWrapper">
|
|
||||||
{{ form.cc_myself.errors }}
|
|
||||||
<label for="id_cc_myself">CC yourself?</label>
|
|
||||||
{{ form.cc_myself }}
|
|
||||||
</div>
|
|
||||||
<p><input type="submit" value="Send message" /></p>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
Each named form-field can be output to the template using
|
{{ form.non_field_errors }}
|
||||||
``{{ form.name_of_field }}``, which will produce the HTML needed to display the
|
<div class="fieldWrapper">
|
||||||
form widget. Using ``{{ form.name_of_field.errors }}`` displays a list of form
|
{{ form.subject.errors }}
|
||||||
errors, rendered as an unordered list. This might look like::
|
<label for="id_subject">Email subject:</label>
|
||||||
|
{{ form.subject }}
|
||||||
|
</div>
|
||||||
|
<div class="fieldWrapper">
|
||||||
|
{{ form.message.errors }}
|
||||||
|
<label for="id_message">Your message:</label>
|
||||||
|
{{ form.message }}
|
||||||
|
</div>
|
||||||
|
<div class="fieldWrapper">
|
||||||
|
{{ form.sender.errors }}
|
||||||
|
<label for="id_sender">Your email address:</label>
|
||||||
|
{{ form.sender }}
|
||||||
|
</div>
|
||||||
|
<div class="fieldWrapper">
|
||||||
|
{{ form.cc_myself.errors }}
|
||||||
|
<label for="id_cc_myself">CC yourself?</label>
|
||||||
|
{{ form.cc_myself }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Rendering form error messages
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The price of this flexibility of course is more work. Until now we haven't had
|
||||||
|
to worry about how to display form errors, because that's taken care of for us.
|
||||||
|
In this example we have had to make sure we take care of any errors for each
|
||||||
|
field and any errors for the form as a whole. Note ``{{ form.non_field_errors
|
||||||
|
}}`` at the top of the form and the template lookup for errors on each field.
|
||||||
|
|
||||||
|
Using ``{{ form.name_of_field.errors }}`` displays a list of form errors,
|
||||||
|
rendered as an unordered list. This might look like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<ul class="errorlist">
|
<ul class="errorlist">
|
||||||
<li>Sender is required.</li>
|
<li>Sender is required.</li>
|
||||||
|
@ -282,7 +563,9 @@ errors, rendered as an unordered list. This might look like::
|
||||||
|
|
||||||
The list has a CSS class of ``errorlist`` to allow you to style its appearance.
|
The list has a CSS class of ``errorlist`` to allow you to style its appearance.
|
||||||
If you wish to further customize the display of errors you can do so by looping
|
If you wish to further customize the display of errors you can do so by looping
|
||||||
over them::
|
over them:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% if form.subject.errors %}
|
{% if form.subject.errors %}
|
||||||
<ol>
|
<ol>
|
||||||
|
@ -297,32 +580,34 @@ over them::
|
||||||
Non-field errors (and/or hidden field errors that are rendered at the top of
|
Non-field errors (and/or hidden field errors that are rendered at the top of
|
||||||
the form when using helpers like ``form.as_p()``) will be rendered with an
|
the form when using helpers like ``form.as_p()``) will be rendered with an
|
||||||
additional class of ``nonfield`` to help distinguish them from field-specific
|
additional class of ``nonfield`` to help distinguish them from field-specific
|
||||||
errors. For example, ``{{ form.non_field_errors }}`` would look like::
|
errors. For example, ``{{ form.non_field_errors }}`` would look like:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
<ul class="errorlist nonfield">
|
<ul class="errorlist nonfield">
|
||||||
<li>Generic validation error</li>
|
<li>Generic validation error</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
See :doc:`/ref/forms/api` for more on errors, styling, and working with form
|
||||||
|
attributes in templates.
|
||||||
|
|
||||||
Looping over the form's fields
|
Looping over the form's fields
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
If you're using the same HTML for each of your form fields, you can reduce
|
If you're using the same HTML for each of your form fields, you can reduce
|
||||||
duplicate code by looping through each field in turn using a ``{% for %}``
|
duplicate code by looping through each field in turn using a ``{% for %}``
|
||||||
loop::
|
loop:
|
||||||
|
|
||||||
<form action="/contact/" method="post">
|
.. code-block:: html+django
|
||||||
{% for field in form %}
|
|
||||||
<div class="fieldWrapper">
|
|
||||||
{{ field.errors }}
|
|
||||||
{{ field.label_tag }} {{ field }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
<p><input type="submit" value="Send message" /></p>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
Within this loop, ``{{ field }}`` is an instance of
|
{% for field in form %}
|
||||||
:class:`~django.forms.BoundField`. ``BoundField`` also has the following
|
<div class="fieldWrapper">
|
||||||
attributes, which can be useful in your templates:
|
{{ field.errors }}
|
||||||
|
{{ field.label_tag }} {{ field }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Useful attributes on ``{{ field }}`` include:
|
||||||
|
|
||||||
``{{ field.label }}``
|
``{{ field.label }}``
|
||||||
The label of the field, e.g. ``Email address``.
|
The label of the field, e.g. ``Email address``.
|
||||||
|
@ -341,7 +626,7 @@ attributes, which can be useful in your templates:
|
||||||
some inline JavaScript and want to avoid hardcoding the field's ID.
|
some inline JavaScript and want to avoid hardcoding the field's ID.
|
||||||
|
|
||||||
``{{ field.value }}``
|
``{{ field.value }}``
|
||||||
The value of the field. e.g ``someone@example.com``
|
The value of the field. e.g ``someone@example.com``.
|
||||||
|
|
||||||
``{{ field.html_name }}``
|
``{{ field.html_name }}``
|
||||||
The name of the field that will be used in the input element's name
|
The name of the field that will be used in the input element's name
|
||||||
|
@ -360,7 +645,9 @@ attributes, which can be useful in your templates:
|
||||||
``{{ field.is_hidden }}``
|
``{{ field.is_hidden }}``
|
||||||
This attribute is ``True`` if the form field is a hidden field and
|
This attribute is ``True`` if the form field is a hidden field and
|
||||||
``False`` otherwise. It's not particularly useful as a template
|
``False`` otherwise. It's not particularly useful as a template
|
||||||
variable, but could be useful in conditional tests such as::
|
variable, but could be useful in conditional tests such as:
|
||||||
|
|
||||||
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% if field.is_hidden %}
|
{% if field.is_hidden %}
|
||||||
{# Do something special #}
|
{# Do something special #}
|
||||||
|
@ -373,11 +660,11 @@ attributes, which can be useful in your templates:
|
||||||
``{{ char_field.field.max_length }}``.
|
``{{ char_field.field.max_length }}``.
|
||||||
|
|
||||||
Looping over hidden and visible fields
|
Looping over hidden and visible fields
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
If you're manually laying out a form in a template, as opposed to relying on
|
If you're manually laying out a form in a template, as opposed to relying on
|
||||||
Django's default form layout, you might want to treat ``<input type="hidden">``
|
Django's default form layout, you might want to treat ``<input type="hidden">``
|
||||||
fields differently than non-hidden fields. For example, because hidden fields
|
fields differently from non-hidden fields. For example, because hidden fields
|
||||||
don't display anything, putting error messages "next to" the field could cause
|
don't display anything, putting error messages "next to" the field could cause
|
||||||
confusion for your users -- so errors for those fields should be handled
|
confusion for your users -- so errors for those fields should be handled
|
||||||
differently.
|
differently.
|
||||||
|
@ -385,22 +672,21 @@ differently.
|
||||||
Django provides two methods on a form that allow you to loop over the hidden
|
Django provides two methods on a form that allow you to loop over the hidden
|
||||||
and visible fields independently: ``hidden_fields()`` and
|
and visible fields independently: ``hidden_fields()`` and
|
||||||
``visible_fields()``. Here's a modification of an earlier example that uses
|
``visible_fields()``. Here's a modification of an earlier example that uses
|
||||||
these two methods::
|
these two methods:
|
||||||
|
|
||||||
<form action="/contact/" method="post">
|
.. code-block:: html+django
|
||||||
{# Include the hidden fields #}
|
|
||||||
{% for hidden in form.hidden_fields %}
|
{# Include the hidden fields #}
|
||||||
{{ hidden }}
|
{% for hidden in form.hidden_fields %}
|
||||||
{% endfor %}
|
{{ hidden }}
|
||||||
{# Include the visible fields #}
|
{% endfor %}
|
||||||
{% for field in form.visible_fields %}
|
{# Include the visible fields #}
|
||||||
<div class="fieldWrapper">
|
{% for field in form.visible_fields %}
|
||||||
{{ field.errors }}
|
<div class="fieldWrapper">
|
||||||
{{ field.label_tag }} {{ field }}
|
{{ field.errors }}
|
||||||
</div>
|
{{ field.label_tag }} {{ field }}
|
||||||
{% endfor %}
|
</div>
|
||||||
<p><input type="submit" value="Send message" /></p>
|
{% endfor %}
|
||||||
</form>
|
|
||||||
|
|
||||||
This example does not handle any errors in the hidden fields. Usually, an
|
This example does not handle any errors in the hidden fields. Usually, an
|
||||||
error in a hidden field is a sign of form tampering, since normal form
|
error in a hidden field is a sign of form tampering, since normal form
|
||||||
|
@ -412,15 +698,14 @@ Reusable form templates
|
||||||
|
|
||||||
If your site uses the same rendering logic for forms in multiple places, you
|
If your site uses the same rendering logic for forms in multiple places, you
|
||||||
can reduce duplication by saving the form's loop in a standalone template and
|
can reduce duplication by saving the form's loop in a standalone template and
|
||||||
using the :ttag:`include` tag to reuse it in other templates::
|
using the :ttag:`include` tag to reuse it in other templates:
|
||||||
|
|
||||||
<form action="/contact/" method="post">
|
.. code-block:: html+django
|
||||||
{% include "form_snippet.html" %}
|
|
||||||
<p><input type="submit" value="Send message" /></p>
|
# In your form template:
|
||||||
</form>
|
{% include "form_snippet.html" %}
|
||||||
|
|
||||||
# In form_snippet.html:
|
# In form_snippet.html:
|
||||||
|
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="fieldWrapper">
|
<div class="fieldWrapper">
|
||||||
{{ field.errors }}
|
{{ field.errors }}
|
||||||
|
@ -430,12 +715,11 @@ using the :ttag:`include` tag to reuse it in other templates::
|
||||||
|
|
||||||
If the form object passed to a template has a different name within the
|
If the form object passed to a template has a different name within the
|
||||||
context, you can alias it using the ``with`` argument of the :ttag:`include`
|
context, you can alias it using the ``with`` argument of the :ttag:`include`
|
||||||
tag::
|
tag:
|
||||||
|
|
||||||
<form action="/comments/add/" method="post">
|
.. code-block:: html+django
|
||||||
{% include "form_snippet.html" with form=comment_form %}
|
|
||||||
<p><input type="submit" value="Submit comment" /></p>
|
{% include "form_snippet.html" with form=comment_form %}
|
||||||
</form>
|
|
||||||
|
|
||||||
If you find yourself doing this often, you might consider creating a custom
|
If you find yourself doing this often, you might consider creating a custom
|
||||||
:ref:`inclusion tag<howto-custom-template-tags-inclusion-tags>`.
|
:ref:`inclusion tag<howto-custom-template-tags-inclusion-tags>`.
|
||||||
|
|
Loading…
Reference in New Issue