Back to home

HTMX and Wagtail CMS quickstart

Table of Contents

Installing HTMX

The first step to using HTMX with any project is loading it into the environment. That can be achieved by following the installation instructions on their website.

Serving content in a view

Within the app of your choice, I’ll call mine htmxdemo, add the following to views.py:

# htmxdemo/views.py

from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.views import View

class ExampleView(View):
    def get(self, request, *args, **kwargs):
        context = {
            "request": request,
            # Any other data the template requires
        }

        # Load in the content from a template, passing the current context
        template_content = render_to_string(
            "htmxdemo/example.html", context
        )

        # Return the template content within a HttpResponse
        return HttpResponse(
            mark_safe(template_content),
            content_type="text/html",
        )

For the above example to work, we’ll need to create the htmxdemo/example.html file within a templates folder. Here’s mine:

<!-- htmxdemo/example.html -->

<p>Hello, world!</p>

Next, in htmxdemo/urls.py, we need to load in the View we created:

# htmxdemo/urls.py

from django.urls import path
from ticketingstack.views import ExampleView

urlpatterns = [
    path("example/", ExampleView.as_view(), name="example_view"),
]

And, finally, we just need to load the app’s URLs in our project’s main URLs file. We do this by adding the path of the desired app to the urlpatterns list:

# project_dir/urls.py

# ...

urlpatterns = [
    # ... Existing urls

    path(
        "htmxdemo/",
        include(("htmxdemo.urls", "htmxdemo"), namespace="htmxdemo"),
    ),
]

# ...

And that’s it! You can now visit http://127.0.0.1:8000/htmxdemo/example , and you should see the content from your HTML template.

A screenshot of a browser at the /htmxdemo/example endpoint, showing 'Hello world' as the content.

Next steps

From here, you can extend the ExampleView.get method to be smarter, utilising the request arg to access URL parameters or other pieces of information about the request to dynamically change the content served, just like your standard Django workflow.

You can then continue with HTMX as normal, using the new endpoint to dynamically load in content as needed.

Related blogs

  • django-testing-patterns
    Useful Django unit test patterns

    This is a collection of some common unit test patterns I find myself re-implementing across various projects. To save myself (and maybe some others) time in the future, I've decided to collect them all in one place.

    20 March 2026
  • writing-wagtail-streamfield-content-migrations
    Writing Wagtail StreamField content migrations

    When you drastically change one of your StreamFields and generate a migration for your new structure, the migration won't actually update what's already in your database. It'll describe the new, intended structure behind the fields, but the JSON data itself will remain exactly as it is.

    18 February 2026
  • directly-filtering-wagtail-pages
    Directly filtering Wagtail parent/child pages

    In Wagtail, pages don't have a typical, direct relationship like you'd expect in Django. Instead of using foreign keys to link them, each page has a `path` and a `depth` attribute...

    24 November 2025