SECRET OF CSS

How to Handle Full-page Reloads With Django and HTMX | by John Galiszewski | Jul, 2022


Exploring use-case scenarios.

1*8odNSEl6 NwsE7KXT5431w

A common problem you may encounter, when using HTMX with Django, is handling full-page reloads while using the hx-target attribute along with hx-push-url. There are a few options we can use when tackling this issue.

  • Option one is to add a custom event listener to every template with a partial who’s url is pushed to the browser’s history with hx-push-url.
  • Option two is extending Django’s default TemplateResponseMixin to handle HTMX requests.
  • Option three involves creating a custom middleware class and using the process_template_request method.

This article assumes you’ve started a new Django project, included HTMX in your static files, and installed the django-htmx app.

Option one is ideal if you only need to handle the full-page reload of one or two views in your entire project since it doesnt follow DRY principals.

This option is very straight forward. When the template is loaded it will get the view that belongs to the provided url and render the response inside of the provided target.

Note: This may not be the traditional event listener you are accustomed to. From the HTMX Docs.

The hx-trigger attribute allows you to specify what triggers an AJAX request.

And “load” is described as a non-standard event supported by HTMX.

This option is best for when you want to handle htmx requests in most of your views but not necessarily all of them. We start with creating our custom mixin classHtmxResponseMixin and inheriting Django’s TemplateResponseMixin. From there we’re going to override the get_template_names method.

Inside of get_template_names, we need to get the name of the app our requested view belongs to. To do that, we need to include an app namespace in our project’s urls. For example:

Finally, we check the request for an htmx instance and return the proper template.

Template setup

Now when we add our mixin to a view, for example:

If the request was made by htmx it will render our partial template, if not a full-page template will be returned. To avoid re-writing our content for each page we can set up our templates in a way that plays well with django.

First we set up a base.html file in the templates directory.

Then we set up the template_name.html file in the templates/app_name directory.

Finally we can create the partial template file in the templates/app_name/partials directory. In there we can check the request for an htmx instance do things like update the page title, breadcrumbs or even include messages with Django’s messages framework. Below that is the normal canvas content which again will be rendered by using the {% include %} template tag within the full-page template or via an htmx request.

By now you can see how we use htmx to interact with our app to create an SPA-like interface. Option three takes this concept a step further using custom middleware.

The final option works in a similar fashion to the second, but is more implicit. We start with defining our middleware class, and by default it requires the __init__ method to accept a get_response argument.

Next is the __call__ method which is called every time a request is made. For now it only needs to return a response object for the process_template_response method to handle. This special method is a middleware hook, which is called after a view is finished executing.

Inside of process_template_response we begin to see the similarities to option two. Our applications still require a namespace, but after that we need to create a new list in the settings.py file called HTMX_APPS and check if the request belongs to an app in this list. While in the settings, we can add our class to the MIDDLEWARE list.

This is so our custom middleware class only affects apps we explicity define, preventing errors with other third-party apps such as the default django admin application.

Finally we check the request for an htmx instance, supply the response’s template_name attribute with the proper template and return the response object, which must implement a render method. This means any of django’s default class-based views will work well with this middleware class.

The template setup follows the same method as option 2.

In the next post I’ll be showing how we can build a highly dynamic SPA-like application using these practices.



News Credit

%d bloggers like this: