Build Django Forms with Crispy Forms and Bootstrap 5

Learn to create visually appealing and responsive forms in Django using crispy forms and Bootstrap 5. Simplify layouts and save time.

How to Create Forms in Django Using Crispy Forms and Bootstrap 5

Django provides an excellent way to manage forms, but making them visually appealing often requires additional work. django-crispy-forms simplifies this process by integrating seamlessly with Bootstrap 5, allowing you to build beautiful and responsive forms effortlessly.

In this guide, I will show you how to use crispy forms to create a form in Django. This will include various field types such as input, textarea, select, checkbox, and file upload. We will also organize the fields into a responsive layout with rows and columns.


Why Use Crispy Forms?

Crispy forms offer several advantages:

  1. Cleaner Templates: You can define your form's layout and styling in Python, which reduces the need for repetitive HTML in your templates.
  2. Bootstrap Integration: Out-of-the-box support for Bootstrap 5 ensures your forms look polished and responsive.
  3. Reusable Helpers: Form helpers allow you to centralize styling and behavior, making your code more maintainable.

Setting Up Crispy Forms

To start, install the required packages:

pip install django-crispy-forms crispy-bootstrap5

Next, update your settings.py file:

INSTALLED_APPS = [
    # Other apps...
    'crispy_forms',
    'crispy_bootstrap5',
]

CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

Creating the Model

Let's define a model to represent the data for our form:

from django.db import models

class ExampleModel(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    category = models.CharField(
        max_length=50,
        choices=[('A', 'Category A'), ('B', 'Category B'), ('C', 'Category C')]
    )
    agree_to_terms = models.BooleanField()
    file_upload = models.FileField(upload_to='uploads/')

    def __str__(self):
        return self.name

This model includes various field types: CharField for input, TextField for textarea, CharField with choices for a dropdown, BooleanField for a checkbox, and FileField for file upload.

Creating the Form

Now, let's create a form using Django's ModelForm and integrate crispy forms with a layout helper. To do that we can define a property called helper in our form using the @property decorator.

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Row, Column, Submit
from .models import ExampleModel

class ExampleForm(forms.ModelForm):
    class Meta:
        model = ExampleModel
        fields = ['name', 'description', 'category', 'agree_to_terms', 'file_upload']

    @property
    def helper(self):
        helper = FormHelper()
        helper.form_method = 'post'
        helper.layout = Layout(
            Row(
                Column('name', css_class='col-md-6'),
                Column('category', css_class='col-md-6'),
            ),
            'description',
            Row(
                Column('file_upload', css_class='col-md-6'),
                Column('agree_to_terms', css_class='col-md-6'),
            ),
            Submit('submit', 'Submit', css_class='btn-primary')
        )
        return helper

The @property decorator allows us to define a reusable helper for the form. This helper sets up the form method and organizes fields into a Bootstrap layout with rows and columns.

Rendering the Form in a Template

To render the form in a template, use the crispy forms tag. Create a new HTML file, for example, example_form.html:

{% load crispy_forms_tags %}

<form method="post" enctype="multipart/form-data">
  {% csrf_token %} {% crispy form %}
</form>

This template will automatically apply the Bootstrap 5 styling and layout defined in the form helper.


Styling Forms with Custom CSS

While django-crispy-forms provides a sufficient default styling with Bootstrap 5, there may be times when you want to add your own custom styles. You can still use crispy forms' helper for layout and structure while applying your CSS to achieve a unique look.

Here’s how you can add custom styling to a form:


Step 1: Add Custom CSS Classes in the Form

In the form definition, you can add custom CSS classes to individual fields using the FormHelper object:

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Row, Column, Submit, Field
from .models import ExampleModel

class StyledExampleForm(forms.ModelForm):
    class Meta:
        model = ExampleModel
        fields = ['name', 'description', 'category', 'agree_to_terms', 'file_upload']

    @property
    def helper(self):
        helper = FormHelper()
        helper.form_method = 'post'
        helper.layout = Layout(
            Row(
                Column(Field('name', css_class='custom-input-class'), css_class='col-md-6'),
                Column(Field('category', css_class='custom-select-class'), css_class='col-md-6'),
            ),
            Field('description', css_class='custom-textarea-class'),
            Row(
                Column(Field('file_upload', css_class='custom-file-class'), css_class='col-md-6'),
                Column(Field('agree_to_terms', css_class='custom-checkbox-class'), css_class='col-md-6'),
            ),
            Submit('submit', 'Submit', css_class='custom-submit-class')
        )
        return helper

Here, Field is used to wrap each form field, allowing you to add custom CSS classes to it.


Step 2: Write Custom CSS

Now that you’ve added custom classes to the form fields, you can define styles in your CSS file. Create or update a CSS file in your Django app’s static directory. For example:

static/css/custom_form_styles.css

.custom-input-class {
  border: 2px solid #007bff;
  border-radius: 5px;
  padding: 10px;
  font-size: 16px;
}

.custom-select-class {
  background-color: #f8f9fa;
  border: 1px solid #ced4da;
  border-radius: 5px;
  padding: 8px;
}

.custom-textarea-class {
  border: 2px dashed #6c757d;
  border-radius: 5px;
  padding: 12px;
  font-size: 14px;
}

.custom-file-class {
  border: 2px dotted #28a745;
  padding: 8px;
  border-radius: 5px;
  color: #28a745;
}

.custom-checkbox-class {
  margin-top: 10px;
  transform: scale(1.2);
}

.custom-submit-class {
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 5px;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
}

.custom-submit-class:hover {
  background-color: #0056b3;
}

Step 3: Load the CSS File in the Template

To apply your custom styles, include the CSS file in your template. Make sure the STATICFILES_DIRS and STATIC_URL are correctly set up in your Django project.

In your template:

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- Import your custom css file here -->
    <link rel="stylesheet" href="{% static 'css/custom_form_styles.css' %}" />
    <title>Styled Form</title>
  </head>
  <body>
    <form method="post" enctype="multipart/form-data">
      {% csrf_token %} {{ form|crispy }}
    </form>
  </body>
</html>

With this setup, your form fields will now have the custom styles applied. This approach allows you to use the power of crispy forms for layout and responsiveness while applying your unique design elements to the forms.


Final Thoughts

Using django-crispy-forms with Bootstrap 5 is a very easy and fast way for creating forms in Django. It simplifies layout management, makes your templates cleaner, and ensures your forms are responsive and visually appealing. While there are some minor limitations, such as dependency on specific Bootstrap versions, the benefits make it a must-have tool for most of your Django projects.

Whether you're building a simple contact form or a more complex data entry system, crispy forms can save you time and effort while delivering professional-looking results.

More posts in Python