Best approach for theming auto-generated forms

Hello, Django folks!

I’m looking for the best way to theme auto-generated forms from LoginView and apply Bootstrap 5 styling. Specifically, I’m wondering if it’s possible to add CSS classes to input fields without having to re-implement the form in forms.py or manually write out each field in registration/login.html (i.e., using the auto-generated form).

I’ve come across solutions that involve looping over the form fields and applying a custom filter to add classes to specific HTML tags, as shown below:

templatetags/custom_filters.py:

from django import template

register = template.Library()

@register.filter(name='addclass')
def addclass(field, css_class):
    return field.as_widget(attrs={'class': css_class})

registration/login.html

{% load custom_filters %}
<form method="post" class="text-center">
    {% csrf_token %}
    <div class="form-group">
        {# Styling auto-generated fields #}
        {% for field in form %}
            <div class="form-row">
                {{ field.label_tag }}{{ field|addclass:"form-control" }} <!-- Adding class directly to auto-generated form fields -->
                {{ field.errors }}
            </div>
        {% endfor %}
    </div>
</form>

Additionally, I’ve considered using FORM_RENDERER and customizing widget templates.

What I want to achieve is the ability to apply Bootstrap 5 classes to the auto-generated forms with minimal boilerplate.

Is there a more elegant or simpler solution for this without unverified 3rd-party modules? I’d love to hear the community’s thoughts and suggestions.

Thanks in advance!

Using templatetag to apply a class? That is convoluted.

You can achieve the same in form fields when defining the Form. Check out the following documentation of Styling Widget Instances.

After embedding the required css classes as per attrs, Django will expand them in the template when generating the forms.

Thanks for the response! Let me clarify my situation a bit.

I’m using the permission_required() decorator in my views, which redirects users to the login_url when they aren’t authenticated. As I understand it, Django’s built-in LoginView automatically provides a form that renders in registration/login.html.

In this case, I want to apply Bootstrap 5 classes to the form without writing any additional Python code (like manually defining a form in forms.py). The beauty of LoginView is that it just works out of the box, and I’m trying to avoid touching the backend logic for this basic use case.

I get that defining the form fields with custom widget attributes in Python is one way to style forms, but my goal is to do everything in the template with minimal setup. That’s why I explored using a template tag to apply CSS classes directly to the auto-generated form fields.

I hope this makes more sense now!

Thanks again for the input, and I’m open to any other suggestions for keeping the code as streamlined as possible.

Welcome @pravorskyi !

<opinion>
It seems to me that you’re spending a lot of time worrying about not overridding a default, when you would have been done with this by creating your own template right away. I think you’ve spent more time trying to find an alternative.
</opinion>

The defaults are just that - defaults. It is expected that you would be overridding those defaults when necessary.

So yes, the simple, direct, and “Djangoish” answer is to create your own registration/login.html template styled as you see fit.

1 Like

Fair point, @KenWhitesell! :smile:

With the little free time I have to dig into the framework, I figured I might as well explore extra possibilities. But you’re right — sometimes the simplest path is the best one.

That said, I’ll let this one be solved for now and take your advice. If I encounter more auto-generated forms down the road, maybe I’ll revisit this whole deep dive.