Create A Django Form With Django Crispy Forms And HTMX.

A form is an essential part of most web applications, as it is used to collect input from users. Django is a Python web framework that provides a way to create forms without having to write HTML code. But creating forms the traditional way in Django can be tedious and time-consuming. In this tutorial, you will learn how to create a Django form with Django Crispy Forms, and the new JavaScript library, HTMX.

With these tools, you can quickly and easily create beautiful, responsive forms that are easy to maintain and update. By the end of this tutorial, you will have a basic understanding of how to use Django Crispy Forms and HTMX to create forms in Django.

Prerequisites

For you to fully understand this article and follow along, you need to fulfill the following prerequisites:

  1. Sound knowledge of HTML forms.

  2. Good understanding of Django views, URL patterns, and templates.

  3. Basic understanding of how requests work

What Are Django Forms?

Django forms are a crucial part of the Django web framework for handling user input. They make it easy to create and manage forms for collecting user data in a web application. Django forms are used to validate and process user input before storing it in the database or performing other operations as required.

Django Crispy Forms And HTMX.

Django Crispy Forms is a third-party package for the Django web framework that makes it easier to create and style forms. It provides a simple, consistent, and flexible way to handle form layouts and rendering. It can be used to automatically generate Bootstrap forms as well as perform tasks such as customizing form rendering on a per-field or per-form basis and generating error messages as well. It can also render forms using template packs different from Bootstrap.

HTMX is a JavaScript library that allows you to update parts of your website with new HTML content without having to reload the page. It lets you handle form submissions, fetch data from the server, and update parts of the page without having to refresh the entire page.

Create A Project In Django.

The first step to successfully creating a form with Django is to create a Django project.

Step 1: Open your terminal or command line interface and navigate to your project directory.

Step 2: Install Django by typing the following:

pip install django

This will install the latest version of Django. You can specify a particular version to install. For example:

pip install django==3.0

Django 3.0 will be installed.

install Django

Step 3: Create a Django project. To do this, type the following command:

django-admin startproject your_project_name

This will create a project directory with the project name you specify. You can open the folder in vscode to verify this.

create a project from the command line

view project on vscode

Step 4: Create a Django app. This can be achieved with the following command:

python manage.py startapp your_app_name

A subdirectory will be created. You can learn more about the differences between an app and a project in Django, here.

create Django app

Creating Your Django Form.

Before diving into the creation of a form, I will explain how forms work in Django. All forms in Django inherit from the Django built-in Form class. The Form class defines fields such as text fields, checkboxes, radio buttons, and select lists, which are used in everyday forms. Each field can be customized with labels, validation rules, etc. Once defined, these fields will be mapped to HTML input fields.

Once a Form class is created, it can be rendered in the templates. It can also be processed by the logic written in the views. The process of creating a form in Django is almost the same as creating a model. To create one, follow this syntax:

from django import forms # make necessary imports

class FormName(forms.Form): # inherit from Django Form class
    field_name = forms.Field_name(**options) # this will be mapped as an HTML input field

Step 5: Create a forms.py file in your app directory.

create forms.py file

Step 6: Inside the [forms.py](http://forms.py)`` file, create a form of your choice using the syntax above. I will create a student enrollment form.

from django import forms

COURSE_CHOICES =(
    (1, 'Law'),
    (2, 'Computer Science'),
    (3, 'Business Administration'),
)
class EnrollmentForm(forms.Form):
    name = forms.CharField()
    age = forms.IntegerField()
    course = forms.ChoiceField(choices=COURSE_CHOICES)
    dob = forms.DateField()

In the code snippet above, I have created an instance of a form and defined four fields in it. I also have a tuple called COURSE_CHOICES. It contains a list of tuples, each one representing a course. The four fields in EnrollmentForm are name, age, course, and dob. The name and age fields are character and integer fields, respectively. They accept no parameters. The third field is a choice field. It will be displayed as a drop-down selection menu. It takes a parameter called choices. It is assigned to the COURSE_CHOICES tuple I earlier created. The options in the resulting drop-down will be the courses available in the tuple. Finally, the dob field is a date field. It will be used to accept the user’s date of birth.

Step 7: To visualize the form in the browser, you need to add it to your views.py file and pass it to your template.

# views.py file
from django.shortcuts import render
from .forms import EnrollmentForm # import the form from forms.py
# Create your views here.

def form(request):
    context = {
        'form': EnrollmentForm() # pass form into the context
    }
    return render(request, 'form_app/index.html', context) # Render the template with the context data and return it as the response to the client's request
# template file
{% extends 'form_app/base.html' %}

{% block content %}

{{form}}
{% endblock %}

Step 8: Make sure to include your project in the settings.INSTALLED_APPS. After this, type, python manage.py runserver in your terminal.

 python manage.py runserver

Next, copy the localhost url and paste it into your browser. You should see a form. Make sure you configure your urls.py file correctly as well.

add app to settings.py file

run the server and copy the url

paste url in browser

Step 9: Modify the form to allow each input field to be on a separate line.

# template file
{% extends 'form_app/base.html' %}

{% block content %}

{{form.as_p}}
{% endblock %}

modify the form to stack each input field

Adding Crispy Forms And HTMX To Your Django Form

Adding Django Crispy Forms

Step 1: Install Django Crispy Forms with the pip command:

pip install django-crispy-forms

install Django crispy forms

Step 2: Add crispy_forms to your installed apps.

add crispy_forms to installed apps

Step 3: Add CRISPY_TEMPLATE_PACK = 'bootstrap' to your settings file. This will let Django know that you are using Bootstrap.

add crispy forms template pack to settings

Step 4: Add crispy_forms_tags to your template file and render the form with it. Your form should look different.

{% extends 'form_app/base.html' %}
{% load crispy_forms_tags %} #load crispy_forms_tag

{% block content %}

{% crispy form %} # render your form with the crispy tag

{% endblock %}

new look of form with crispy

Step 5: Change the drop-down field to radio buttons and modify the date field. Django forms allow you to specify the widget you want when creating each field. To do this, modify your forms.py file and add the necessary widgets. Run the server and view your form. It should be different.

from django import forms
from datetime import datetime

COURSE_CHOICES =(
    (1, 'Law'),
    (2, 'Computer Science'),
    (3, 'Business Administration'),
)
class EnrollmentForm(forms.Form):
    name = forms.CharField()
    age = forms.IntegerField()
    course = forms.ChoiceField(
        choices=COURSE_CHOICES,
        widget=forms.RadioSelect # change widget to radio select
    )
    dob = forms.DateField(
        widget=forms.DateInput(attrs={  # change widget to date widget
        'type': 'date', 
        'max': datetime.now().date()})) # prevent users from entering a future date

change widgets in the form

Step 6: Add a form method and a form action. Crispy forms allows you to add a method and action to your forms with ease while making use of the FormHelper class made available. The FormHelper helps you control the behavior of your form when rendered. It uses Python, so you will worry less about HTML codes. Modify your forms.py file to this:

from django import forms
from datetime import datetime

# new imports
from django.urls import reverse_lazy # for form action
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit # for submit button

COURSE_CHOICES =(
    (1, 'Law'),
    (2, 'Computer Science'),
    (3, 'Business Administration'),
)
class EnrollmentForm(forms.Form):
    def __init__(self, *args, **kwargs): 
        super().__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.form_action = reverse_lazy('form') #direct form action to the form() view
        self.helper.form_method = 'GET' # change form method to GET
        self.helper.add_input(Submit('submit', 'Submit')) # add submit button

    name = forms.CharField()
    age = forms.IntegerField()
    course = forms.ChoiceField(
        choices=COURSE_CHOICES,
        widget=forms.RadioSelect #change widget to radio select
    )
    dob = forms.DateField(
        widget=forms.DateInput(attrs={  # change widget to date widget
        'type': 'date', 
        'max': datetime.now().date()})) #prevent users from entering a future date

In the above code, I used the __init__() function to initialize the helper attribute and create an instance of FormHelper.

self.helper = FormHelper(self)

To set the form action, I used the reverse_lazy() function. It works similarly to the url template tag. Here, I set the form action to go to the form() view. I also set the form method accordingly.

Lastly, I created a button for the form by making use of the Submit class available in crispy_forms.layout.

self.helper.add_input(Submit('submit', 'Submit'))

To visualize the changes, run your server, refresh your page, and inspect it. You should notice the changes in the markup.

add form method, action, and button

Integrating HTMX Into Your Django Form.

You should be ready to add HTMX attributes to your form now. To do this, follow the following steps:

Step 1: Add the HTMX CDN to your template file. I will add mine to my base.html file.

<script src="<https://unpkg.com/htmx.org@1.6.1>"></script>

Step 2: Add HTMX attributes to form. This will be done in a similar way to when the DateInput widget was added to the dob field. I will add HTMX attributes to the name field. You can add them to any field you want. Modify the field like this:

name = forms.CharField(
        widget=forms.TextInput(
            attrs={
                'hx-trigger': 'keyup',
                'hx-get': reverse_lazy('form')
            }
        )
    )

You can add as many attributes as you want, and to any of your desired fields. To view the result of this, refresh your page and inspect it. You should see the attributes in the HTML markup.

view htmx attributes in the browser

Switch to your network tab, clear it, and fill in the field you modified earlier. You will notice that you are sending HTMX Ajax requests as you type.

testing htmx attributes in the network tab

Another way to confirm this is by looking at your dev server. You should see GET requests coming in.

view htmx get requests in terminal

Conclusion

In this article, you have learned how to create a basic form with Django Crispy Forms and HTMX. In the next article, you will learn how to handle requests when the submit button is clicked. To truly understand how forms work in Django, you will need to practice them as often as possible. For further reading, you can check out these sources:

Django Forms: https://docs.djangoproject.com/en/4.1/topics/forms/

HTMX: https://htmx.org/docs/

Django Crispy Forms: https://django-crispy-forms.readthedocs.io/en/latest/

You can connect with me on Twitter. If you have any questions, please drop them in the comment section, and if you have found this article helpful, leave a like and share it with your friends. If you need the source code used in this article, you can find it here.

1
Subscribe to my newsletter

Read articles from Ademola Thompson directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ademola Thompson
Ademola Thompson

Ademola is a backend developer with experience with Django, a Python web framework. He enjoys teaching others what he knows about the web; hence he decided to become a technical content writer. Once in a while, he explores the possibilities of Solidity and Web 3.0. He is popularly known as SuperheroJT.