About this document
This document provides an introduction to Django’s form handling features. For a more detailed look at specific areas of the forms API, see The Forms API, Form fields, and Form and field validation.
django.forms
is Django’s form-handling library.
While it is possible to process form submissions just using Django’s
HttpRequest
class, using the form library takes care of a
number of common form-related tasks. Using it, you can:
The library deals with these concepts:
<input type="text">
or <textarea>
. This handles rendering of the
widget as HTML.EmailField
that makes sure its data is a valid email address.The library is decoupled from the other Django components, such as the database
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).
A Form object encapsulates a sequence of form fields and a collection of
validation rules that must be fulfilled in order for the form to be accepted.
Form classes are created as subclasses of django.forms.Form
and
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 personal Web site:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(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
fields: subject
, message
, sender
and cc_myself
. CharField
,
EmailField
and BooleanField
are just three of the available field types;
a full list can be found in Form fields.
If your form is going to be used to directly add or edit a Django model, you can use a ModelForm to avoid duplicating your model description.
The standard pattern for processing a form in a view looks like this:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
There are three code paths here:
request.POST
. If the submitted data is valid, it is processed
and the user is re-directed to a “thanks” page.The distinction between bound and unbound forms is important. An unbound form does not have any data associated with it; when rendered to the user, it will be empty or will contain default values. A bound form does have submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered it can include inline error messages telling the user where they went wrong.
See Bound and unbound forms for further information on the differences between bound and unbound forms.
To see how to handle file uploads with your form see Binding uploaded files to a form for more information.
Once is_valid()
returns True
, you can process the form submission safe
in the knowledge that it conforms to the validation rules defined by your form.
While you could access request.POST
directly at this point, it is better to
access form.cleaned_data
. This data has not only been validated but will
also be converted in to the relevant Python types for you. In the above example,
cc_myself
will be a boolean value. Likewise, fields such as IntegerField
and FloatField
convert values to a Python int and float respectively. Note
that read-only fields are not available in form.cleaned_data
(and setting
a value in a custom clean()
method won’t have any effect) because these
fields are displayed as text rather than as input elements, and thus are not
posted back to the server.
Extending the above example, here’s how the form data could be processed:
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
from django.core.mail import send_mail
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/') # Redirect after POST
For more on sending email from Django, see Sending email.
Forms are designed to work with the Django template language. In the above
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 %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
The form only outputs its own fields; it is up to you to provide the surrounding
<form>
tags and the submit button.
Forms and Cross Site Request Forgery protection
Django ships with an easy-to-use protection against Cross Site Request
Forgeries. When submitting a form via POST with
CSRF protection enabled you must use the 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
wrapped in a paragraph. Here’s the output for our example template:
<form action="/contact/" method="post">
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
<input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
<input type="text" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<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
is referenced by the accompanying label tag. This is important for ensuring
forms are accessible to assistive technology such as screen reader software. You
can also customize the way in which labels and ids are generated.
You can also use form.as_table
to output table rows (you’ll need to provide
your own <table>
tags) and form.as_ul
to output list items.
If the default generated HTML is not to your taste, you can completely customize the way a form is presented using the Django template language. Extending the above example:
<form action="/contact/" method="post">
{{ 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.name_of_field }}
, which will produce the HTML needed to display the
form widget. Using {{ form.name_of_field.errors }}
displays a list of form
errors, rendered as an unordered list. This might look like:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
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
over them:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
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 %}
loop:
<form action="/contact/" method="post">
{% 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 BoundField
.
BoundField
also has the following attributes, which can be useful in your
templates:
{{ field.label }}
Email address
.{{ field.label_tag }}
<label>
tag,
e.g. <label for="id_email">Email address</label>
{{ field.value }}
someone@example.com
{{ field.html_name }}
{{ field.help_text }}
{{ field.errors }}
<ul class="errorlist">
containing any validation errors
corresponding to this field. You can customize the presentation of
the errors with a {% for error in field.errors %}
loop. In this
case, each object in the loop is a simple string containing the error
message.field.is_hidden
This attribute is True
if the form field is a hidden field and
False
otherwise. It’s not particularly useful as a template
variable, but could be useful in conditional tests such as:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
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
using the include
tag to reuse it in other templates:
<form action="/contact/" method="post">
{% include "form_snippet.html" %}
<p><input type="submit" value="Send message" /></p>
</form>
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
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 include
tag:
<form action="/comments/add/" method="post">
{% include "form_snippet.html" with form=comment_form %}
<p><input type="submit" value="Submit comment" /></p>
</form>
If you find yourself doing this often, you might consider creating a custom inclusion tag.
This covers the basics, but forms can do a whole lot more:
See also
Nov 29, 2016