One of my favorite parts of working at Caktus is the community of developers who share knowledge within and outside our teams. Many of us work on different projects, but still take time to come together, share what we've learned, and apply those learnings to other projects.
As an example, this past Monday Karen Tracey offered to give an overview of HTMX for the team. The talk was informal but well attended, and other team members chimed in to share different things they'd learned recently about using HTMX on a Django project, too.
The Problem
During this talk, I was particularly delighted by a solution Karen and her team developed to properly handle Django's login_required decorator when applied to HTMX or hybrid HTMX/HTML views. The middleware helps properly handle redirects when a session times out and the user attempts to POST to an HTMX view. In other words, if the user's session times out, we want to gracefully take them through the login form and back to where they were on the site. Without this middleware the user might see nothing at all to indicate a problem, or might find a (likely non-functional) login page suddenly embedded in the middle of the page they are working with.
HTMX Redirect Middleware
Without further ado, here's the middleware the team put together to solve this problem:
from urllib.parse import urlparse
def htmx_middleware(get_response):
def middleware(request):
response = get_response(request)
# HTMX request returning 302 likely is login required.
# Take the redirect location and send it as the HX-Redirect header value,
# with 'next' query param set to where the request originated. Also change
# response status code to 204 (no content) so that htmx will obey the
# HX-Redirect header value.
if (
request.headers.get("HX-Request") == "true"
and response.status_code == 302
):
ref_header = request.headers.get("Referer", "")
if ref_header:
referer = urlparse(ref_header)
querystring = f"?next={referer.path}"
else:
querystring = ""
redirect = urlparse(response["location"])
response.status_code = 204
response.headers["HX-Redirect"] = f"{redirect.path}{querystring}"
return response
return middleware
It's worth noting this middleware, for simplicity's sake, treats any redirect as a redirect through the login page. If you plan to use this on views that might generate other types of redirects, you'll want to ensure they're excluded properly when the middleware runs.
Conclusion
If you're using HTMX on a Django project, this middleware might help you gracefully handle redirects in case a user's session times out. If you use it, please provide any feedback in the comments below. Similarly, if you've found other ways to solve this particular problem when using HTMX with Django, please let us know in the comments below.