The quickest way to customize the form’s presentation is with CSS. The list of errors in particular could do with some visual enhancement, and the <ul> has a class attribute of errorlist for that exact purpose. The following CSS really makes our errors stand out:
<style type=”text/css”>
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
While it’s convenient to have our form’s HTML generated for us, in many cases the default rendering won’t be right for our application. {{ form.as_table }} and friends are useful shortcuts while we develop our application, but everything about the way a form is displayed can be overridden, mostly within the template itself.
Each field widget (<input type=”text”>, <select>, <textarea>, or similar) can be rendered individually by accessing {{ form.fieldname }}. Any errors associated with a field are available as {{ form.fieldname.errors }}. We can use these form variables to construct a custom template for our contact form:
<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>
{{ 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.
Specifying labels
By default, the labels on Django’s auto-generated form HTML are created by replacing underscores with spaces and capitalizing the first letter – so the label for the email field is “Email“. (Sound familiar? It’s the same simple algorithm that Django’s models use to calculate default verbose_name values for fields.) But, as with Django’s models, we can customize the label for a given field. Just use label, like so:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False, label=’Your e-mail address’)
message = forms.CharField(widget=forms.Textarea)
Customizing Form Design
Our contact_form.html template uses {{ form.as_table }} to display the form, but we can display the form in other ways to get more granular control over display. The quickest way to customize forms’ presentation is with CSS. Error lists, in particular, could do with some visual enhancement, and the auto-generated error lists use <ul class=”errorlist”> precisely so that you can target them with CSS. Add the following CSS in the <head></head> section of contact_form.html to really make our errors stand out (Figure 6-9):
<style type=”text/css”>
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 1.2em;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
While it’s convenient to have our form’s HTML generated for us, in many cases you’ll want to override the default rendering. {{ form.as_table }} and friends are useful shortcuts while you develop your application, but everything about the way a form is displayed can be overridden, mostly within the template itself, and you’ll probably find yourself doing this.
Each field’s widget (<input type=”text”>, <select>, <textarea>, etc.) can be rendered individually by accessing {{ form.fieldname }} in the template, and any errors associated with a field are available as {{ form.fieldname.errors }}. With this in mind, we can construct a custom template for our contact form with the following template code:
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style=”color: red;”>
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action=”” method=”post”>
<div class=”field”>
{{ form.subject.errors }}
<label for=”id_subject”>Subject:</label>
{{ form.subject }}
</div>
<div class=”field”>
{{ form.email.errors }}
<label for=”id_email”>Your e-mail address:</label>
{{ form.email }}
</div>
<div class=”field”>
{{ form.message.errors }}
<label for=”id_message”>Message:</label>
{{ form.message }}
</div>
{% csrf_token %}
<input type=”submit” value=”Submit”>
</form>
</body>
</html>
In the above template code, {{ form.message.errors }} displays a <ul class=”errorlist”> if errors are present and a blank string if the field is valid (or the form is unbound). This is the same for the other fields on our contact form.
We can also treat form.message.errors as a Boolean or even iterate over it as a list. This is useful when there can be multiple errors associated with a field. For example:
<div class=”field{% if form.message.errors %} errors{% endif %}”>
{% if form.message.errors %}
<ul>
{% for error in form.message.errors %}
<li><strong>{{ error }}</strong></li>
{% endfor %}
</ul>
{% endif %}
<label for=”id_message”>Message:</label>
{{ 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 associated with the message field in an unordered list.