Trey Hunner

Python & Django on-site team training

Hire Me For Training

CSS classes and Django form fields

| Comments

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
from django import forms

class AuthenticationForm(forms.Form):
    username = forms.CharField(max_length=254)
    password = forms.CharField(widget=forms.PasswordInput)

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
from django import forms

class AuthenticationForm(forms.Form):
    username = forms.CharField(
        max_length=254,
        widget=forms.TextInput(attrs={'class': "input-lg"}),
    )
    password = forms.CharField(widget=forms.PasswordInput)

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:

  1. add_class template filter
  2. render_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.

Like my teaching style?

Want to learn more about Python? I share my favorite Python resources and answer Python questions every week through live chats. Sign up below and I’ll answer your questions about how to make your Python code more descriptive, more readable, and more Pythonic.


Comments