htmx.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. from urllib.parse import urlsplit
  2. from django.http import HttpResponse
  3. from django.urls import reverse
  4. __all__ = (
  5. 'htmx_current_url',
  6. 'htmx_maybe_redirect_current_page',
  7. 'htmx_partial',
  8. )
  9. def htmx_partial(request):
  10. """
  11. Determines whether to render partial (versus complete) HTML content
  12. in response to an HTMX request, based on the target element.
  13. """
  14. return request.htmx and not request.htmx.boosted
  15. def htmx_current_url(request) -> str:
  16. """
  17. Extracts the current URL from the HTMX-specific headers in the given request object.
  18. This function checks for the `HX-Current-URL` header in the request's headers
  19. and `HTTP_HX_CURRENT_URL` in the META data of the request. It preferentially
  20. chooses the value present in the `HX-Current-URL` header and falls back to the
  21. `HTTP_HX_CURRENT_URL` META data if the former is unavailable. If neither value
  22. exists, it returns an empty string.
  23. """
  24. return request.headers.get('HX-Current-URL') or request.META.get('HTTP_HX_CURRENT_URL', '') or ''
  25. def htmx_maybe_redirect_current_page(
  26. request, url_name: str, *, preserve_query: bool = True, status: int = 200
  27. ) -> HttpResponse | None:
  28. """
  29. Redirects the current page in an HTMX request if conditions are met.
  30. This function checks whether a request is an HTMX partial request and if the
  31. current URL matches the provided target URL. If the conditions are met, it
  32. returns an HTTP response signaling a redirect to the provided or updated target
  33. URL. Otherwise, it returns None.
  34. """
  35. if not htmx_partial(request):
  36. return None
  37. current = urlsplit(htmx_current_url(request))
  38. target_path = reverse(url_name) # will raise NoReverseMatch if misconfigured
  39. if current.path.rstrip('/') != target_path.rstrip('/'):
  40. return None
  41. redirect_to = target_path
  42. if preserve_query and current.query:
  43. redirect_to = f'{target_path}?{current.query}'
  44. resp = HttpResponse(status=status)
  45. resp['HX-Redirect'] = redirect_to
  46. return resp