Django Crispy forms [How to Implement in Django Form]

Django Crispy forms

Hello Techies,

In this blog, we are going to check how to implement the Django Crispy Forms to make Forms effective and user friendly with its features. So you can make your login, registration, and other templates interactive using Django Crispy Form.

Let’s check Django crispy forms layout examples.

List of contents

  1. Introduction (What is crispy forms?)
  2. Installation
  3. Django Basic Forms Rendering
  4. Django Crispy Forms Rendering
  5. Django Crispy Forms Field Customization
  6. Advance Features of Django Crispy Forms

1. Introduction (What is Django crispy forms?)

Django Crispy Forms is a third-party application used to manage Django Forms. This allows you to adjust the properties of the form (such as method and CSS class) on the back-end without rewriting the template.


2. Installation

To install Django crispy forms you need to use python package manager “pip” or “easy_install”

Use the below command to install django-crispy-forms: 

pip install django-crispy-forms

Add this application to the INSTALLED_APPS list after installation. You can check out their official site to learn more about this application and more advanced options.

 INSTALLED_APPS = [
    ... #existing apps

    'crispy_forms',
]

CRISPY_TEMPLATE_PACK = 'bootstrap4' 

Download compatible latest Bootstrap 4 CSS and JS files and keep them in your static folder which is always a good practice instead of adding a hosted Bootstrap CDN URL. For now, I’m using the CDN version.

Below is the base HTML that we extend to all our templates to avoid duplication.

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>TechPlusLifeStyle - Django Crispy Forms</title>

  <!-- Bootstrap core CSS -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>

<body>

  <!-- Navigation -->
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
    <div class="container">
      <a class="navbar-brand" href="#">LOGO</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ml-auto">
          <li class="nav-item active">
            <a class="nav-link" href="{% url 'home' %}">Home
              <span class="sr-only">(current)</span>
            </a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{% url 'basic_product_view' %}">Basic Product View</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{% url 'crispy_product' %}">Crispy Product View</a>
          </li>
        </ul>
      </div>
    </div>
  </nav>

  <!-- Page Content -->
  <div class="container">
    <div class="row">
      <div class="col-lg-12">
        {% block content %}
        {% endblock %}
      </div>
    </div>
  </div>

  <!-- Bootstrap core JavaScript -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js" integrity="sha384-LtrjvnR4Twt/qOuYxE721u19sVFLVSA4hf/rRt6PrZTmiPltdZcI7q7PXQBYTKyf" crossorigin="anonymous"></script>
</body>

</html>

Below is the models.py file which we are using for both examples with and without Crispy forms.

#models.py

from django.db import models

class Products(models.Model):
    class Meta:
        db_table = 'products'

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=150)
    price = models.DecimalField(max_digits=20, decimal_places=2, default = 0.0)
    category = models.CharField(max_length=150)
    description = models.TextField()

3. Django Basic Forms Rendering

Let’s check the basic form rendering without using any CSS.

The Python code to represent the product detail form is as follows.

#urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('basic_product/', views.BasicProductView.as_view(), name="basic_product_view"),

]
#views.py

from django.views.generic import CreateView

from .models import Products

class BasicProductView(CreateView):
    model = Products
    template_name = 'basic_product_view.html'
    fields = ['name', 'price', 'category', 'description']
    success_url = "/basic_product"

Template View

Create separate html (basic_product_view.html) for basic product view and add the below code in it. In this template we will extend the base.html and render the Create-view of Basic Product view and form.

{% extends 'base.html' %}
{% block content %}
  <h1>Add Product</h1>
  <form method="post" novalidate>
    {% csrf_token %}
    <table>{{ form }}</table>
    <button type="submit" class="btn btn-success">Save</button>
  </form>
{% endblock %}

Rendered HTML

form without Django crispy forms

Rendered HTML with validation


4. Django Crispy Forms Rendering

Template code as in the previous example using crispy_forms_tags.

Template View

{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block content %}
  <h1>Add Product</h1>
  <form method="post" novalidate>
    {% csrf_token %}
    {{ form|crispy }}
    <button type="submit" class="btn btn-success">Save</button>
  </form>
{% endblock %}

Rendered HTML

Django Crispy forms

Rendered HTML with validation


5. Django Crispy Forms Field Customization

If you want to customize the form field, you can manually render the field using the as_crispy_field template filter.

Template View

{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block content %}
  <h1>Add Product</h1>
  <form method="post" novalidate>
    {% csrf_token %}
    <div class="row">
      <div class="col-6">
        {{ form.name|as_crispy_field }}
      </div>
      <div class="col-6">
        {{ form.category|as_crispy_field }}
      </div>
    </div>
    <div class="row">
      <div class="col-6">
        {{ form.price|as_crispy_field }}
      </div>
    </div>
    <div class="row">
      <div class="col-6">
        {{ form.description|as_crispy_field }}
      </div>
    </div>
    <button type="submit" class="btn btn-success">Save</button>
  </form>
{% endblock %}

Rendered HTML

Django Crispy Forms Field Customization

Rendered HTML with validation


6. Advance Features of Django Crispy Forms

Django Crispy Forms offers FormHalper classes that allow us to use form properties. So, let’s see how to use this FormHalper class and its properties.

# forms.py

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit

from .models import Products

class ProductForm(forms.ModelForm):
    class Meta:
        model = Products
        fields = ['name', 'price', 'category', 'description']  # list of fields you want from model

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.attrs = {'novalidate': ''}
        self.helper.form_method = 'post'  # get or post method
        self.helper.form_id = 'product_info'
        self.helper.form_class = 'product_details'
        self.helper.add_input(Submit('submit', 'Save'))

The main logic in the __init__ method.In this method we are calling the formalper class and its properties. Using the helper function we can call the form attributes like form method, form id, form class as well as we can change the label name of Submit button.

# view.py
from django.views.generic import CreateView

from .models import Products
from .forms import ProductForm

class AdvanceCrispyProductView(CreateView):
    model = Products
    form_class = ProductForm
    template_name = 'advance_crispy_product_view.html'
    success_url = "/advance_crispy_product"

Template View

Here we will call the {% crispy %} template tag and pass form instance as a parameter.

{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block content %}
  <h1>Add Product</h1>
  {% crispy form %}
{% endblock %}

Crispy Form Layout Helpers

Let’s add a layout to the form. To get this feature we need to call the Layout helper in the __init__ method. Check the code below for this implementation.

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

from .models import Products

class ProductForm(forms.ModelForm):
    class Meta:
        model = Products
        fields = ['name', 'price', 'category', 'description']  # list of fields you want from model

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.attrs = {'novalidate': ''}
        self.helper.form_method = 'post'  # get or post method
        self.helper.form_id = 'product_info'
        self.helper.form_class = 'product_details'
        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'),
                Column('category', css_class='form-group col-md-6 mb-0'),
                css_class='form-row'
            ),
            'description',
            Submit('submit', 'Save')
        )

Rendered HTML

Rendered HTML with validation

Django-crispy-forms layout examples

I hope you understand all the steps on how to use Django Crispy Forms. This application provides many additional features so that you can check out the official site.

Find the source code for Django crispy-forms Github link at https://github.com/pranalikambli/django_crispy_forms

thank you

Leave a Comment