Adding a class 'is-invalid' to input form in Django

How to add bootstrap class is-invalid to Django input forms (only if the form/field is not correctly completed).

My forms.py

class BasicUserDataForm(forms.Form):
    error_css_class = 'is-invalid'
    user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                                             'class': 'form-control'}))

My templates.html

<div class="form-group col-md-6">
  <!-- Label -->
  <label for="id_user_name">Username*</label>
  <div class="input-group mb-0">
    <div class="input-group-prepend">
      <div class="input-group-text">@</div>
    </div>
    {{ form.user_name }}
  </div>
  {% if form.user_name.errors|striptags %}<small class="text-danger"><b>{{ form.user_name.errors|striptags }}</b></small>{% endif %}
</div>

I try:

1.)

class BasicUserDataForm(forms.Form):
    user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                                             'class': 'form-control'}))

2.)

class BasicUserDataForm(forms.Form):
    user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                                             'class': 'form-control {% if form.user_name.errors %}is-invalid{% endif %}'}))

3.) According to the documentation

class BasicUserDataForm(forms.Form):
    error_css_class = 'is-invalid'
    [...]

4.)

.error input, .error select {
    border: 2px red solid;
}

It still doesn't give any results. I would like to get the effect that gives:

user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                                             'class': 'form-control is-invalid'}))

enter image description here


Try adding a Meta class to your form and assigning the proper model. For instance:

class BasicUserDataForm(forms.Form):
  error_css_class = 'is-invalid'
  user_name = forms.CharField(max_length=20, widget=forms.TextInput(attrs={'placeholder': 'Username', 'class': 'form-control'})) 

  class Meta:
    model = User    

Create a file, yourapp_template-filters.py
and then place it in templatetags folder in your app:

from django import template
register = template.Library()


@register.filter(name='add_attr')
def add_attribute(field, css):
    attrs = {}
    definition = css.split(',')

    for d in definition:
        if ':' not in d:
            attrs['class'] = d
        else:
            key, val = d.split(':')
            attrs[key] = val

    return field.as_widget(attrs=attrs)

To use it in a Django template, firstly add this widget in the top of the template, similar to the load static widget:
{% load yourapp_template-filters %}
And now you can use it on any form widget as a function, like so:

{% if form.user_name.errors %}
     {{ form.user_name|add_attr:"form-control is-invalid" }}
{% else %}
     {{form.user_name|add_attr:"form-control"}}
{% endif %}