Learn Django crispy forms bootstrap 4 ( how to use crispy forms in django ). Django crispy forms tutorial. Integrating Bootstrap Form with Django is very easy and simple. There are lots of Django Libraries for Bootstrap. In this tutorial, we are going to use django-crispy-forms for Bootstrap Form in Django. Crispy-Forms is a great package that gives good control over rendering Bootstrap form in your Django Project.
How to Install Crispy Forms in Django
For using we Django Crispy Forms Library, we need to install it. We are installing it using pip.
pip install django-crispy-forms
Now add it to your INSTALLED_APPS
and specify which Bootsrap version to use.
INSTALLED_APPS = [ ... 'crispy_forms', ] CRISPY_TEMPLATE_PACK = 'bootstrap4'
Download and Setup Bootstrap Form for Django Project
You can download the latest Bootstrap 4 version from getbootstrap. Then go to the download page and get the Compiled CSS and JS version.
Or if you don’t want to download you can use hosted Bootstrap CDN –
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
For simplicity, I will be using the CDN version. Here is my base.html going to look which is referenced in the below example –
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title>Hello, Django Fans!</title> </head> <body> <div class="container"> <div class="row justify-content-center"> <div class="col-8"> <h1 class="mt-2">Hello Django Fans</h1> <hr class="mt-0 mb-4"> {% block content %} {% endblock %} </div> </div> </div> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>
Some more useful links for Django Template –
- How to Render Dynamic Data in Django Template
- How to Integrate Bootstrap 4 Template in Django
- How to write Django Custom Template Tags and Filters
How to use Crispy Forms in Django Template
Suppose we have a model named Product
as follows –
# models.py from django.db import models class Product(models.Model): name = models.CharField(max_length=130) description = models.TextField(blank=True) price = models.FloatField(blank=True)
Let’s say we want to create a form to add products in the model. For that, we are using CreateView
.
# views.py from django.views.generic import CreateView from .models import Product class ProductCreateView(CreateView): model = Product fields = ('name', 'description', 'price') template_name = 'product.html'
In product.html file will be extended by base.html. In product.html we will render ProductCreateView
and form.
<!-- product.html --> {% extends 'base.html' %} {% block content %} <form method="post"> {% csrf_token %} {{ form }} <button type="submit" class="btn btn-success">Save person</button> </form> {% endblock %}
This is the very basic form rendering. Django will render it with no style just plain fields.

To render the same form with Bootstrap classes, do the following –
<!-- product.html --> {% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %} <form method="post" novalidate> {% csrf_token %} {{ form|crispy }} <button type="submit" class="btn btn-success">Save Product</button> </form> {% endblock %}
After using crispy with form, you will see the result like below.

There might be some cases where you want some freedom to render form fields. You can do so by rendering the fields manually and using the as_crispy_field
template filter –
<!-- product.html --> {% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %} <form method="post" novalidate> {% csrf_token %} <div class="row"> <div class="col-6"> {{ form.name|as_crispy_field }} </div> <div class="col-6"> {{ form.price|as_crispy_field }} </div> </div> {{ form.description|as_crispy_field }} <button type="submit" class="btn btn-success">Save Product</button> </form> {% endblock %}

Crispy Forms Helpers Method
Django Crispy Form have a special class method named FormHelper
which gives more control over how to render your forms.
Here is the example of UpdateView using Form –
# forms.py from django import forms from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit from product.models import Product class ProductForm(forms.ModelForm): class Meta: model = Product fields = ('name', 'description', 'price') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_method = 'post' # get or post self.helper.add_input(Submit('submit', 'Save Product'))
The main logic is in __init__()
method. In that method we are calling the Crispy FormHelper
method. Using helper function we are defining POST
method to handle the form. We have also change the submit label with ‘Save Product’.
Now our view, just regular Django code:
# views.py from django.views.generic import UpdateView from .forms import ProductForm class ProductUpdateView(UpdateView): model = Product form_class = ProductForm template_name = 'product-update.html'
Then is our template product-update.html –
<!-- product-update.html --> {% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %} {% crispy form %} {% endblock %}
Here we can simply call the {% crispy %}
template tag and pass our form instance as a parameter.

Advanced Form Rendering using Crispy Forms
This section will explain how to use crispy form feature to handle advance form rendering. Django crispy forms custom template.
Crispy Form Layout Helpers
We can use crispy form helper functions to achieve the same layout as image.
# forms.py from django import forms from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit from product.models import Product from crispy_forms.layout import Layout, Submit, Row, Column class ProductForm(forms.ModelForm): class Meta: model = Product fields = ('name', 'description', 'price') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_method = 'post' # get or post self.helper.layout = Layout( Row( Column('name', css_class='form-group col-md-6 mb-0'), Column('price', css_class='form-group col-md-6 mb-0'), css_class='form-row' ), 'description', Submit('submit', 'Save Product') )
And if you see template implementation is very minimal. You can compare the HTML code from here.
{% extends 'base.html' %} {% load crispy_forms_tags %} {% block content %} {% crispy form %} {% endblock %}

You can find this project on GitHub.