Getting Started
Sample
forms.py
:
from django import forms
TOPIC_CHOICES = (
('general', 'General enquiry'),
('bug', 'Bug report'),
('suggestion', 'Suggestion'),
)
class ContactForm(forms.Form):
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
Note: See Forms from Models, Models…
contact.html
(normally in mysite/templates/app-name/
):
<!doctype html>
<html lang="en">
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
<form action="." method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
Note: See Custom Look and Feel below for details on how to construct a
custom template rather than using form.as_table
app-name/views.py
:
from forms import ContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
else:
form = ContactForm()
Initial Data
Initial data can be set in the form class:
class ContactForm(forms.Form):
message = forms.CharField(
widget = forms.Textarea(),
initial = "Replace with your feedback.")
…or… when the form is created (in app-name/views.py
):
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
else:
initial = {
'sender': 'user@example.com'
}
form = ContactForm(initial = initial)
Processing
app-name/views.py
:
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
topic = form.cleaned_data['topic']
message = form.cleaned_data['message']
sender = form.cleaned_data.get('sender', 'noreply@example.com')
send_mail(
'Feedback from your site, topic: %s' % topic,
message, sender,
['admin@example.com'],
fail_silently = True
)
return HttpResponseRedirect('contact/thanks/')
else:
form = ContactForm(initial = {'sender': 'user@example.com'})
return render_to_response('books/contact.html', {'form': form})
Note:
The forms framework does more than just validate the data, it also converts it into Python types.
To tell whether a form is bound to valid data, call the
is_valid()
method.In the example above, when using email, the
sender
is not required, so we provide a default.We have set the Django
send_mail
method tofail_silently
because we have not set-up our mail server.Having sent the feedback email, we’ll redirect our user to a static confirmation page.
Redirect After POST: If a user selects Refresh on a page that was displayed by a
POST
request, that request will be repeated. This can often lead to undesired behavior, such as a duplicate record being added to the database.Redirect after POST is a useful pattern that can help avoid this scenario: after a successful
POST
has been processed, redirect the user to another page rather than returning HTML directly.
Save
To update a model before saving, you can follow one of the following patterns:
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Note: See the save method for further details…
Custom Look and Feel
Rather than using form.as_table
(see above) we can build our own
custom template:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
<form action="." method="POST">
<div class="fieldWrapper">
{{ form.topic.errors }}
<label for="id_topic">Kind of feedback:</label>
{{ form.topic }}
</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 (optional):</label>
{{ form.sender }}
</div>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
To construct the control, we just use
form.
followed by the name of the field e.g.{{ form.topic }}
.{{ form.message.errors }}
will display as a<ul class="errorlist">
if errors are present and a blank string if the field is valid (or the form is unbound).
We can also treat form.message.errors
as a Boolean
or even iterate
over it as a list, for example:
<div class="fieldWrapper{% if form.message.errors %} errors{% endif %}">
{% if form.message.errors %}
<ol>
{% for error in form.message.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
{{ form.message }}
</div>
In the case of validation errors, this will add an errors
class to the
containing <div>
and display the list of errors in an ordered list.
Don’t forget to include hidden fields in the form. These can be included as follows:
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
Testing
For testing of forms, see Testing.