django-htmx
repository·main·Indexed 24 days ago
https://github.com/adamchainz/django-htmxExtensions for using Django with htmx, providing middleware and utilities to make integration more idiomatic. It includes HtmxMiddleware for detecting HTMX requests via request.htmx, specialized response classes like HttpResponseClientRedirect and HttpResponseClientRefresh, and template tags for loading htmx scripts and handling CSRF tokens.
What's inside django-htmx
- django-htmx provides extensions for using Django with htmx. It is designed to facilitate the integration of htmx's AJAX capabilities within the Django framework.
How the django-htmx extension script works
mainThe
django-htmxextension script is rendered byhtmx_scriptordjango_htmx_scriptwhensettings.DEBUGisTrue.By default, htmx discards response content when encountering HTTP errors. This extension adds an error handler that detects 400, 403, 404, and 500 status codes and replaces the page content with the response body. This allows you to see Django's default error pages (like the 404 or 500 debug pages) directly within the htmx request flow, making debugging significantly easier.
Debug django-htmx examples in the browser
mainWhen exploring the example application, you can use browser developer tools to understand how HTMX is interacting with the server:
- Console: Read the HTMX debug log in the browser's console to see event details.
- Network Tab: Inspect the specific requests made by HTMX to see the payloads and responses.
- Source/Templates: View the HTML source or templates to see embedded HTML comments used for debugging or identification.
- Server Logic: Examine
example/views.pyto see how the Django views handle the HTMX requests.
Optimize partial rendering by swapping the base template
mainIf you do not want to use an external package, you can manually swap the base template used for inheritance based on whether the request is an htmx request.
- In the view: Determine a
base_templatevariable (e.g.,_base.htmlfor full pages and_partial.htmlfor htmx requests) and pass it into the context. - In the template: Use the
{% extends base_template %}tag to dynamically select the layout.
This approach requires maintaining a minimal
_partial.htmlthat contains only the necessary structural elements (like the<main>tag) to wrap the content block.@require_GET def partial_rendering(request: HttpRequest) -> HttpResponse: if request.htmx: base_template = "_partial.html" else: base_template = "_base.html" return render( request, "page.html", { "base_template": base_template, }, ){# page.html #} {% extends base_template %} {% block main %} ... {% endblock %}- In the view: Determine a
Make htmx pass Django's CSRF token
mainWhen using "unsafe" htmx methods like
hx-post, you must ensure htmx sends Django's CSRF token in thex-csrftokenheader. The most efficient way to do this is to add thehx-headersattribute to your<body>tag. This allows all htmx elements to inherit the token.Note: Use the
{{ csrf_token }}template variable rather than the{% csrf_token %}template tag, as the tag renders a hidden input field which is not whathx-headersrequires.<body hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'> ... </body>Configure django-htmx in Django settings
mainTo use
django-htmx, you must add it to yourINSTALLED_APPS.Optionally, you can add
django_htmx.middleware.HtmxMiddlewareto yourMIDDLEWAREsetting. This middleware provides therequest.htmxattribute on the request object, allowing you to inspect HTMX-specific request details in your views.INSTALLED_APPS = [ ..., "django_htmx", ..., ] MIDDLEWARE = [ ..., "django_htmx.middleware.HtmxMiddleware", ..., ]Optimize partial rendering with django-template-partials
mainTo reduce server load and payload size, you can render only the specific part of a template that needs updating during an htmx request. Using the
django-template-partialspackage, you can define reusable sections with the{% partialdef %}tag.- Define the partial: Wrap the section in
{% partialdef name inline %}. Theinlineargument ensures it still renders during a full page load. - Update the view: In your Django view, check
request.htmx. If true, append#partial-nameto your template string.
This allows you to use a single view and template for both full page loads and htmx partial updates.
from django.shortcuts import render from example.models import Country def country_listing(request): template_name = "countries.html" if request.htmx: template_name += "#country-table" countries = Country.objects.all() return render( request, template_name, { "countries": countries, }, )- Define the partial: Wrap the section in
Install django-htmx
mainInstall the package using pip:
python -m pip install django-htmxConfigure type-checking for request.htmx
mainIf you use type-checking (like
django-stubs), you must declare thehtmxattribute on your customHttpRequestclass so that the type checker recognizes theHtmxDetailsobject attached by the middleware.from django.http import HttpRequest as HttpRequestBase from django_htmx.middleware import HtmxDetails class HttpRequest(HttpRequestBase): htmx: HtmxDetailsRun the django-htmx example application
mainTo run the included example application, use
uvto run the management command. This will start the development server.Once running, access the application at
http://127.0.0.1:8000/.uv run --group example manage.py runserverInstall and use htmx extensions
maindjango-htmxvendors the core htmx library via the{% htmx_script %}tag, but it does not include htmx extensions. To use extensions (like the WebSocket extension), you should download the extension scripts and serve them from your own static files rather than using a CDN.Steps to add an extension:
- Download the extension's
.jsfile (e.g., usingcurl) into your project's static directory. - Include the script tag in your base template, ensuring it is placed after the htmx script tag.
Example using the WebSocket extension:
curl -L https://unpkg.com/htmx-ext-ws/dist/ws.min.js -o example/static/htmx-ext-ws.min.js{% load django_htmx static %} <!doctype html> <html> <head> ... {% htmx_script %} <script src="{% static 'htmx-ext-ws.min.js' %}" defer></script> </head> <body> ... </body> </html>- Download the extension's
Set up base templates for django-htmx
mainTo enable full functionality, update your base template (Django or Jinja2) with the following:
- Load the
django_htmxtemplate tags. - Include the
{% htmx_script %}tag in your<head>to load HTMX and thedjango-htmxextension script. - Include the Django CSRF token in your
<body>via thehx-headersattribute to ensure POST requests are authorized.
Example for Django templates:
{% load django_htmx %} <!doctype html> <html> <head> ... {% htmx_script %} </head> <body hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'> ... </body> </html>- Load the