- Working with forms
- HTML forms
- GET and POST
- Django’s role in forms
- Forms in Django
- The Django Form class
- Instantiating, processing, and rendering forms
- Building a form
- The work that needs to be done
- Building a form in Django
- The Form class
- The view
- The template
- More about Django Form classes
- Bound and unbound form instances
- More on fields
- Widgets
- Field data
- Working with form templates
- Form rendering options
- Rendering fields manually
- Rendering form error messages
- Looping over the form’s fields
- Looping over hidden and visible fields
- Reusable form templates
- HTML forms
-
-
Save amelieykw/b75bd4d50c4910fbb91b8443362edc0b to your computer and use it in GitHub Desktop.
Handling forms is a complex business.
- display in a form
- rendered as HTML
- edited using a convenient interface
- returned to the server
- validated
- cleaned up
- then saved or passed on for further processing
Django handles three distinct parts of the work involved in forms:
- preparing and restructuring data to make it ready for rendering
- creating HTML forms for the data
- receiving and processing submitted forms and data from the client
- Forms in Django
- The Django Form class
- Instantiating, processing, and rendering forms
a Form class describes a form and determines how it works and appears.
- a model class’s fields map to database fields
- a form class’s fields map to HTML form
<input>
elements - A
ModelForm
maps a model class’s fields to HTML form<input>
elements via aForm
- this is what the Django admin is based upon.
A form’s fields are themselves classes:
- they manage form data
- perform validation when a form is submitted.
When rendering an object in Django, we generally:
- get hold of it in the view (fetch it from the database, for example)
- pass it to the template context
- expand it to HTML markup using template variables
- 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)
- for editing
- data that we have collated from other sources
- for retrieving from db
- data received from a previous HTML form submission
- for getting input
- Building a form
- The work that needs to be done
- Building a form in Django
- The Form class
- The view
- The template
Suppose:
- create a simple form on your website
- in order to obtain the user's name
<!-- somewhere in your template -->
<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>
- tell the browser to return the form data to the URL
/your-name
- use the
POST
method - display a text field, labeled "Your name:"
- a button marked "OK"
- if the template context contains a
current_name
variable, that will be used to pre-fill theyour_name
field
need a view that renders the template containing the HTML form, and can supply the current_name
field as appropriate.
When the form is submitted, the POST request which is sent to the server will contain the form data.
Then you'll need a view corresponding to that /your-name/
URL which will find the appropriate key/value pairs in the request, and then 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
- use much more complex fields, that allow the user to do things like pick dates from a calendar and so on
We already know what we want our HTML form to look like.
starting point in Django:
# forms.py
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
This defines a Form
class with a single field (your_name
).
We’ve applied a human-friendly label to the field, which will appear in the <label>
when it’s rendered (although in this case, the label we specified is actually the same one that would be generated automatically if we had omitted it).
The field’s maximum allowable length is defined by max_length
.
This does two things:
- It puts a
maxlength="100"
on the HTML<input>
(so the browser should prevent the user from entering more than that number of 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 Form
instance has an 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
cleaned_data
attribute.
The whole form, when rendered for the first time, will look like:
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100" required />
Note that it does not include the
tags, or a submit button. We’ll have to provide those ourselves in the template.
Form data sent back to a Django website is processed by a view, generally the same view which 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:
# views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
<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.
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.
HTML5 input types and browser validation
If your form includes a
URLField
, anEmailField
or any integer field type, Django will use the url, email and number HTML5 input types. By default, browsers may apply their own validation on these fields, which may be stricter than Django’s validation. If you would like to disable this behavior, set the novalidate attribute on the form tag, or specify a different widget on the field, like TextInput.
We now have a working web form, described by a Django 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 prepared to understand other features of the forms system and ready to learn a bit more about the underlying machinery.
- More about Django Form classes
- Bound and unbound form instances
- More on fields
- Widgets
- Field data
All form classes are created as subclasses of either django.forms.Form
or django.forms.ModelForm
.
You can think of ModelForm as a subclass of Form.Form
and ModelForm actually inherit common functionality from a (private) BaseForm class, but this implementation detail is rarely important.
In fact if your form is going to be used to directly add or edit a Django model, a ModelForm 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.
The distinction between Bound and unbound forms is important:
- An unbound form has no data associated with it.
- When rendered to the user, it will be empty or will contain default values.
- A bound form has 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 what data to correct.
The form’s is_bound
attribute will tell you whether a form has data bound to it or not.
Consider a more useful form than our minimal example above, which we could use to implement “contact me” functionality on a personal website:
# forms.py
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. CharField, EmailField and BooleanField are just three of the available field types; a full list can be found in Form fields.
Each form field has a corresponding Widget class, 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 TextInput widget, that produces an <input type="text">
in the HTML. If you needed <textarea>
instead, you’d specify the appropriate widget when defining your form field, as we have done for the message field.
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 nicely converted into Python types for you.
You can still access the unvalidated data directly from
request.POST
at this point, but the validated data is better.
In the contact form example above, cc_myself will be a boolean value. Likewise, fields such as IntegerField and FloatField convert values to a Python int and float respectively.
Here’s how the form data could be processed in the view that handles this form:
# views.py
from django.core.mail import send_mail
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 = ['[email protected]']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
For more on sending email from Django, see Sending email.
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 Binding uploaded files to a form.
- Working with form templates
- Form rendering options
- Rendering fields manually
- Rendering form error messages
- Looping over the form’s fields
- Looping over hidden and visible fields
- Reusable form templates
All you need to do to get your form into a template is to place the form instance into the template context. So if your form is called form in the context, {{ form }}
will render its <label>
and <input>
elements appropriately.
Additional form template furniture
Don’t forget that a form’s output does not include the surrounding
<form>
tags, or the form’s submit control. You will have to provide these yourself.
There are other output options though for the <label>/<input>
pairs:
{{ form.as_table }}
will render them as table cells wrapped in<tr>
tags{{ form.as_p }}
will render them wrapped in<p>
tags{{ 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:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required /></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
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 in ensuring that forms are accessible to assistive technology such as screen reader software. You can also customize the way in which labels and ids are generated.
See Outputting forms as HTML for more on this.
We don’t have to let Django unpack the form’s fields; we can do it manually if we like (allowing us to reorder the fields, for example).
Each field is available as an attribute of the form using {{ form.name_of_field }}
, and in a Django template, will be rendered appropriately. For example:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>