Extensions for using Django with htmx.
Python 3.6 to 3.10 supported.
Django 2.2 to 4.0 supported.
Are your tests slow? Check out my book Speed Up Your Django Tests which covers loads of best practices so you can write faster, more accurate tests.
Install with pip:
python -m pip install django-htmx
Add django-htmx to your
INSTALLED_APPS
:INSTALLED_APPS = [ ..., "django_htmx", ..., ]
Add the middleware:
MIDDLEWARE = [ ..., "django_htmx.middleware.HtmxMiddleware", ..., ]
(Optional) Add the extension script to your template, as documented below.
See the example app in the example/
directory of the GitHub repository for usage of django-htmx.
django-htmx comes with a small JavaScript extension for htmx’s behaviour. Currently the extension only includes a debug error handler, documented below.
The script is served as a static file called django-htmx.js
, but you shouldn’t reference it directly.
Instead, use the included template tags, for both Django and Jinja templates.
For Django Templates, load and use the template tag, after your htmx <script>
tag:
{% load django_htmx %}
{% django_htmx_script %}
For Jinja Templates, you need to perform two steps. First, load the tag function into the globals of your custom environment:
# myproject/jinja2.py
from jinja2 import Environment
from django_htmx.jinja import django_htmx_script
def environment(**options):
env = Environment(**options)
env.globals.update(
{
# ...
"django_htmx_script": django_htmx_script,
}
)
return env
Second, call the function in your template, after your htmx <script>
tag:
{{ django_htmx_script() }}
htmx’s default behaviour when encountering an HTTP error is to discard the response. This can make it hard to debug errors in development.
The django-htmx script includes an error handler that’s active when debug mode is on. The handler detects responses with 404 and 500 status codes and replaces the page with their content. This change allows you to debug with Django’s default error responses as you would for a non-htmx request.
See this in action in the “Error Demo” section of the example app.
This middleware attaches request.htmx
, an instance of HtmxDetails
.
See it action in the “Middleware Tester” section of the example app.
This class provides shortcuts for reading the htmx-specific request headers.
True
if the request was made with htmx, otherwise False
.
This is based on the presence of the HX-Request
header.
This allows you to switch behaviour for requests made with htmx like so:
def my_view(request):
if request.htmx:
template_name = "partial.html"
else:
template_name = "complete.html"
return render(template_name, ...)
True
if the request came from an element with the hx-boost
attribute.
Based on the HX-Boosted
header.
The current URL of the browser, or None
for non-htmx requests.
Based on the HX-Current-URL
header.
True
if the request is for history restoration after a miss in the local history cache.
Based on the HX-History-Restore-Request
header.
The user response to hx-prompt if it was used, or None
.
The id
of the target element if it exists, or None
.
Based on the HX-Target
header.
The id
of the triggered element if it exists, or None
.
Based on the HX-Trigger
header.
The name
of the triggered element if it exists, or None
.
Based on the HX-Trigger-Name
header.
The deserialized JSON representtation of the event that triggered the request if it exists, or None
.
This header is set by the event-header htmx extension, and contains details of the DOM event that triggered the request.
htmx can trigger a client side redirect when it receives a response with the HX-Redirect
header.
HttpResponseClientRedirect
is a HttpResponseRedirect subclass for triggering such redirects.
For example:
from django_htmx.http import HttpResponseClientRedirect
def sensitive_view(request):
if not sudo_mode.active(request):
return HttpResponseClientRedirect("/activate-sudo-mode/")
...
When using a polling trigger, htmx will stop polling when it encounters a response with the special HTTP status code 286.
HttpResponseStopPolling
is a custom response class with that status code.
For example:
from django_htmx.http import HttpResponseStopPolling
def my_pollable_view(request):
if event_finished():
return HttpResponseStopPolling()
...
A constant for the HTTP status code 286, for use with e.g. Django’s render shortcut.
from django_htmx.http import HTMX_STOP_POLLING
def my_pollable_view(request):
if event_finished():
return render("event-finished.html", status=HTMX_STOP_POLLING)
...
Full signature:
def trigger_client_event(
response: HttpResponse,
name: str,
params: dict[str, Any],
*,
after: EventAfterType = "receive"
) -> None:
...
A header modifying function for triggering client-side events via the HX-Trigger
headers.
Takes the name of the event to trigger and any JSON-compatible parameters for it, and stores them in the appropriate header.
The header depends on the value of after
:
"receive"
, the default, maps toHX-Trigger
"settle"
maps toHX-Trigger-After-Settle
"swap"
maps toHX-Trigger-After-Swap
Calling trigger_client_event
multiple times for the same response
and after
will add or replace the given event name and preserve others.
For example:
from django_htmx.http import trigger_client_event
def end_of_long_process(request):
response = render("end-of-long-process.html")
trigger_client_event(
response,
"showConfetti",
{"colours": ["purple", "red", "pink"]},
after="swap",
)
return response