Nifty Django Feature: Form Templates
Title: Nifty Django Feature: Form Templates
URL Source: https://www.better-simple.com/django/2026/07/22/nifty-feature-form-templates/
Published Time: 2026-07-22T00:00:00+00:00
Markdown Content: A nifty feature in Django are the form templates. They are a way to make reusable templates, scoped to the form. They provide separation between the view’s template and how a form is rendered. This separation allows forms to be more reusable.
Typically, a view that processes a form will have a template that includes the following:
```
{% csrf_token %} {{ form }}```
However, pretty quickly you start wanting to customize how that form’s contents get rendered. The inputs need styles and everything needs to look just so, right?
At that point, you need to customize the form’s template which opens a can of forms. The default template has a lot going on in it.
``` {{ errors }} {% if errors and not fields %} {% for field in hidden_fields %}{{ field }}{% endfor %}
{% endif %} {% for field, errors in fields %} {{ field.as_field_group }} {% if forloop.last %} {% for field in hidden_fields %}{{ field }}{% endfor %} {% endif %} {% endfor %} {% if not fields and not errors %} {% for field in hidden_fields %}{{ field }}{% endfor %} {% endif %} ```
In an ideal world, we wouldn’t want our profile_update.html template to contain the above explicitly. Yes, it’s part of rendering the form to update the profile, but the specifics are less so. One option would be to wrap it in a template and use {% include %}. But in that case, the profile_update.html template must know about what form is being passed in and that it has to include a specific template, coupling the form to the view’s template. It’s not the end of the world, but it’s far from ideal.
Form.template_name
This is where setting a template_name on the Form class comes in handy. You can specify the template that should be used when rendering the form.
``` from django import forms
class UpdateProfileForm(forms.Form): template_name = "profile/forms/profile_form_with_image_preview.html" ```
This allows you to limit your customization to a single template, but then attach that template to the form, leaving the view template only needing to render {{ form }}. This eliminates that coupling between the view template and the form that we saw with the {% include %} usage.
Now any view that uses UpdateProfileForm will automatically pick up any changes to the form’s template. In our above example, it would be profile/forms/profile_form_with_image_preview.html.
Field.template_name
Another option is to customize how a specific field is rendered. While it’s possible to define your own widget and customize its template, it’s also possible to define the field’s template that’s passed to BoundField.
class UpdateProfileForm(forms.Form):
image = forms.ImageField(
template_name="forms/fields/image_with_preview.html"
)
If you’re looking for the form field template code to customize, you can find it here or below:
{% if field.use_fieldset %}
<fieldset{% if field.aria_describedby %} aria-describedby="{{ field.aria_describedby }}"{% endif %}>
{% if field.label %}{{ field.legend_tag }}{% endif %}
{% else %}
{% if field.label %}{{ field.label_tag }}{% endif %}
{% endif %}
{% if field.help_text %}<div class="helptext"{% if field.auto_id %} id="{{ field.auto_id }}_helptext"{% endif %}>{{ field.help_text|safe }}</div>{% endif %}
{{ field.errors }}
{{ field }}{% if field.use_fieldset %}</fieldset>{% endif %}
For more information
I am going to refer you to Django’s documentation on the topic. The form field rendering was introduced in the 5.x series of Django, but there’s still plenty of information available on it.
- Configuring rendering of a form’s widget
- Customizing the error list format
- Django Crispy Forms, the third-party package that pushed form field rendering forward
If you have thoughts, comments, or questions, please let me know. You can set up a meeting with me, or find me on the Fediverse, Django Discord server or use email.