Skip to content
Back to top
View this page
Edit this page

# Middleware

class django_htmx.middleware.HtmxMiddleware

  This middleware attaches `request.htmx`, an instance of `HtmxDetails` (below). Your views, and any following middleware, can use `request.htmx` to switch behaviour for requests from htmx. The middleware supports both sync and async modes.

  See it action in the “Middleware Tester” section of the example project.

  Set the `Vary` header for cacheable responses

  If you set HTTP caching headers, ensure any views that switch content with `request.htmx` attributes add the appropriate htmx headers to the `Vary` header, per Django’s documentation section Using `Vary` headers. For example:

      from django.shortcuts import render
      from django.views.decorators.cache import cache_control
      from django.views.decorators.vary import vary_on_headers

      @cache_control(max_age=300)
      @vary_on_headers("HX-Request")
      def my_view(request):
          if request.htmx:
              template_name = "partial.html"
          else:
              template_name = "complete.html"
          return render(request, template_name, ...)

  Hint

  If you are type-checking your Django project, declare `request.htmx` as below in any custom `HttpRequest` classes, per the pattern in django-stubs.

      from django.http import HttpRequest as HttpRequestBase
      from django_htmx.middleware import HtmxDetails

      class HttpRequest(HttpRequestBase):
          htmx: HtmxDetails

class django_htmx.middleware.HtmxDetails

  This class provides shortcuts for reading the htmx-specific request headers.

  __bool__()

    `True` if the request was made with htmx, otherwise `False`. Detected by checking if the `HX-Request` header equals `true`.

    This method allows you to change content for requests made with htmx:

        from django.shortcuts import render

        def my_view(request):
            if request.htmx:
                template_name = "partial.html"
            else:
                template_name = "complete.html"
            return render(request, template_name, ...)

    Return type:

      bool

  boosted: bool

    `True` if the request came from an element with the `hx-boost` attribute. Detected by checking if the `HX-Boosted` header equals `true`.

    You can use this attribute to change behaviour for boosted requests:

        def my_view(request):
            if request.htmx.boosted:
                # do something special
                ...
            return render(...)

  current_url: str | None

    The current URL in the browser that htmx made this request from, or `None` for non-htmx requests. Based on the `HX-Current-URL` header.

  current_url_abs_path: str | None

    The absolute-path form of `current_url`, that is the URL without scheme or netloc, or `None` for non-htmx requests.

    This value will also be `None` if the scheme and netloc do not match the request. This could happen if the request is cross-origin, or if Django is not configured correctly.

    For example:

        >>> request.htmx.current_url
        'https://example.com/dashboard/?year=2022'
        >>> # assuming request.scheme and request.get_host() match:
        >>> request.htmx.current_url_abs_path
        '/dashboard/?year=2022'

    This is useful for redirects:

        if not sudo_mode_active(request):
            next_url = request.htmx.current_url_abs_path or ""
            return HttpResponseClientRedirect(f"/activate-sudo/?next={next_url}")

  history_restore_request: bool

    `True` if the request is for history restoration after a miss in the local history cache. Detected by checking if the `HX-History-Restore-Request` header equals `true`.

  prompt: str | None

    The user response to hx-prompt if it was used, or `None`. For htmx 4, this requires loading the `hx-prompt` extension, which restores the `hx-prompt` attribute and its header.

  ptag: str | None

    htmx 4 only

    The polling tag sent by the `hx-ptag` extension in the `HX-PTag` request header, or `None`. You may want to use the `django_htmx.http.ptag()` view decorator to handle this header, rather than reading it directly.

  request_type: str | None

    htmx 4 only

    Indicates if this is a partial or full page request, taking the values `"full"`, `"partial"`, or `None` for non-htmx requests. Based on the `HX-Request-Type` header.

  source: str | None

    htmx 4 only

    A representation of the element that triggered the request, in the form `tag#id` (for example `button#submit`), or `None`. Based on the `HX-Source` header.

  target: str | None

    The target element if it exists, or `None`. Based on the `HX-Target` header, which changed format in htmx 4 per the migration guide.

  trigger: str | None

    htmx 2 only

    The `id` of the triggered element if it exists, or `None`. Based on the `HX-Trigger` header.

  trigger_name: str | None

    htmx 2 only

    The `name` of the triggered element if it exists, or `None`. Based on the `HX-Trigger-Name` header.

  triggering_event: Any | None

    The deserialized JSON representation 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.