Build a Simple CRM With Django and HTMX — Project Setup
Introduction to backend development

In my last article, I wrote about handling htmx page reloads using mixins/middleware. In this article, we’ll be using the final option from the previous tutorial, or you can use the package I’ve put together, django-htmx-refresh
.
Objective
My goal for this series is to teach you how to create a dynamic CRUD application to keep track of clients and their contact information using Django and htmx.
Prerequisites
I’ll be using the following software:
As well as a few additional Django packages:
django-htmx 1.12.0
django-htmx-refresh 0.0.7
Don't forget to create a virtual environment and install these requirements there. I won’t be covering how to create a virtual environment in this article.
Note: I’ll be loading the htmx and Bootstrap documents from a CDN, but both documentations recommend you install them locally during production.
Project Setup
Let’s start by creating our Django project.
python3 -m django startproject simple_crm
Inside the project directory, there is another directory by the same name containing the project's settings; Rename this directory core to avoid any confusion. After that, we need to change some settings for our project to work correctly.
In asgi.py, wsgi.py, and manage.py change the following line:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'simple_crm.settings')
to:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
Now we can add all the settings we’ll need in our settings.py
:
A new configuration you’ll notice is HTMX_APPS
; Utilized by the django_htmx_refresh
app. It ensuresHtmxResponseMiddleware
only affects apps we explicitly define, preventing errors with the default Django admin or other third-party apps. It also requires an application namespace, which we’ll define later in the core/urls.py.
Next, we’ll create the templates directory inside of our project directory.
cd simple_crm
mkdir templates
Then we can start the client_relationship_manager
application.
python3 manage.py startapp client_relationship_manager
At this point, your project directory will look something like this:

Creating the Backend
When starting a new application, I like to write the models first; This gives us something to connect our views to when we get to them. Here we’ll create a model called Client
which will store a client's contact information.
Models
URLs
Next, we’ll establish the URLs our app will need. Inside the core/urls.py, we’ll quickly include our new app’s urls.py file, which we’ll create next. Don’t forget to add an application namespace for the django_htmx_refresh
app to use.
Now we create the client_relationship_manager/urls.py file and add the paths to our basic CRUD views. We’ll also add names to our URL patterns to perform URL reversing.
Views
Now we can create our views. We’ll be inheriting ListView
for our homepage and search results page. The rest will be generic CRUD views.
Notice how each view defines a template_name
. The HtmxResponseMiddleware
intercepts the template_name
attribute then determines if the response has an htmx instance attached to it and returns the appropriate template. We’ll also pass a form_class
to the CreateClientView
and UpdateClientView
Next, inside of SearchResultsView
, we’ll override the get_queryset
method. Inside that method, we’ll get the query from the request, filter all Client
objects by the given search query, and return the results.
Finally, override get_success_url
in the create, update, and delete views. They need to return a success message and render the proper URL.
Forms
We create custom form classes to add class selectors to each form element without writing the forms out manually. It also allows us the option to expand form functionality in the future.
Starting the Server
Let's start the server now, beginning with making the necessary migrations.
python3 manage.py makemigrations
python3 manage.py migrate
Then create a superuser by running the below command and following the prompt in the terminal.
python3 manage.py createsuperuser
Now start the server by running:
python3 manage.py runserver
Finally, visit http://127.0.0.1:8000/ in your web browser. You’ll see a TemplateDoesNotExist
error similar to this image:

Be sure Django is checking for the index.html
file inside templates/crm
as seen above. If it isn't, that means the HtmxResponseMiddleware
isn't aware of the client_relationship_manager
application and you need to check the HTMX_APPS
setting.
Conclusion
The backend is ready to go. In part two of this series, we’ll build our templates and start getting our hands dirty with htmx. I recommend reading my first article if you'd like to learn more about the HtmxResponseMiddleware
we used here today.
Update: Let’s finish this app in Part two!