Django forms provide input validation and HTML form field generation. They also integrate nicely with models. However, Django itself does not allow one-off customizations of form-generated HTML.
In this post I will discuss a method for customizing the HTML generated by Django form fields, with the specific goal of adding custom CSS classes to Django form fields.
Here’s a Django form definition:
1 2 3 4 5 |
|
Here’s the form used in a template:
{{ form.as_p }}
The Problem
We’re using Bootstrap and we want to add an input-lg
CSS class onto our username field to make it really big.
The Solution(s)
There are many ways to solve this problem. I will discuss some solutions I dislike before I discuss my preferred solution.
Using a form widget attribute
We could add a class
attribute to our Django form field:
1 2 3 4 5 6 7 8 |
|
I dislike this approach because it requires including presentation rules in our back-end code. This class attribute is used exclusively by our CSS and/or JavaScript and should therefore live in Django templates, not in Python code.
Using django-floppyforms
If we’re using django-floppyforms we could include logic in our floppyforms/attrs.html
template to add specific classes based on a context variable (example). Here’s an example:
{% for name, value in attrs.items %} {{ name }}{% if value != True %}="{{ value }}{% if name == "class" %} {{ extra_classes }}{% endif %}"{% endfor %}
This should work but it’s ugly and in general I do not enjoy maintaining heavy logic in my templates.
Using django-widget-tweaks
I prefer to solve this problem with django-widget-tweaks.
The django-widget-tweaks library provides two solutions to this problem:
add_class
template filterrender_field
template tag.
The add_class template filter
Mikhail Korobov originally created the django-widget-tweaks library in 2011. It started as a series of template filters for modifying form field attributes from your Django templates.
Here’s an example usage of the add_class
filter for adding a CSS class to our form field:
{% load widget_tweaks %}
<p>
{{ form.username|add_class:"input-lg" }}
{{ form.username.errors }}
</p>
<p>
{{ form.password }}
{{ form.password.errors }}
</p>
I find this solution both easy to read and easy to maintain.
The render_field template tag
I discovered django-widget-tweaks shortly after Mikhail created it. I appreciated his solution for this problem, but I wanted a more HTML-like syntax for my form field customizations. I created the render_field
template tag to satisfy that desire.
With the render_field
tag you can add attributes to form fields with a much more HTML-like syntax:
{% load widget_tweaks %}
<p>
{% render_field form.username class+="input-lg" %}
{{ form.username.errors }}
</p>
<p>
{% render_field form.password %}
{{ form.password.errors }}
</p>
As a bonus, with render_field
we can also set a CSS class for erroneous and required form fields. See the documentation for more details.
Conclusion
I have not had a chance to use django-floppyforms yet, but I expect that django-widget-tweaks and django-floppyforms would integrate well together.
I am on the lookout for new solutions to this problem, but django-widget-tweaks has served me well so far. I have used it for three years now it remains one of my go-to libraries for new Django projects.
How do you add CSS classes do your Django form fields? If you have another solution please leave a comment below.