# Best approach for theming auto-generated forms

**URL:** <https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518>\
**Category:** Templates & Frontend\
**Created:** [September 5, 2024, 1:58pm UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518 "2024-09-05T13:58:00Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![pravorskyi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pravorskyi/32/23691_2.png) [@pravorskyi](https://forum.djangoproject.com/u/pravorskyi)\
**Post date:** [September 5, 2024, 1:58pm UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518/1 "2024-09-05T13:58:00Z")

</div>

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:**

```auto
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**

```auto
{% 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!

---

<div class="post-metadata">

**Author:** ![onyeibo](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/onyeibo/32/11494_2.png) [@onyeibo](https://forum.djangoproject.com/u/onyeibo)\
**Post date:** [September 5, 2024, 2:35pm UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518/2 "2024-09-05T14:35:50Z")

</div>

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](https://docs.djangoproject.com/en/5.1/ref/forms/widgets/#styling-widget-instances).

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

---

<div class="post-metadata">

**Author:** ![pravorskyi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pravorskyi/32/23691_2.png) [@pravorskyi](https://forum.djangoproject.com/u/pravorskyi)\
**Post date:** [September 5, 2024, 5:51pm UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518/3 "2024-09-05T17:51:38Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 5, 2024, 6:01pm UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518/4 "2024-09-05T18:01:26Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![pravorskyi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/pravorskyi/32/23691_2.png) [@pravorskyi](https://forum.djangoproject.com/u/pravorskyi)\
**Post date:** [September 6, 2024, 7:06am UTC](https://forum.djangoproject.com/t/best-approach-for-theming-auto-generated-forms/34518/5 "2024-09-06T07:06:47Z")

</div>

Fair point, @KenWhitesell! 😄

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.
