from django.http import HttpResponse from django.template.loader import render_to_string from django_htmx.http import HttpResponseClientRedirect, HttpResponseClientRefresh class HTMXPartialMixin: """Mixin that automatically switches to a partial template when the request is made via HTMX.""" partial_template_name = None def get_template_names(self): # If HTMX request and a partial is defined, return it if getattr(self.request, "htmx", False) and self.partial_template_name: return [self.partial_template_name] return super().get_template_names() class HTMXViewMixin: """ A full featured HTMX integration mixin for Django CBVs. Supports: - partial rendering via django-partials - HX-Redirect - HX-Push-URL - HX-Trigger events - HX-Refresh - Graceful fallback to normal DJango rendering """ # Name of the partial block: template.html#partial_name partial_name = None # Optional: automatically push URL on GET htmx_push_url = None # Optional: trigger events after rendering htmx_trigger = None htmx_trigger_after_settle = None htmx_trigger_after_swap = None # Optional: redirect target for HTMX htmx_redirect_url = None # Optional: refresh the page htmx_refresh = False def render_partial(self, context): """Render a django-partials block.""" request = self.request return render_to_string(self.partial_name, context, request=request) def apply_htmx_headers(self, response): """Attach HX-* headers to the response.""" request = self.request if request.htmx: is_get = request.method == "GET" is_pagination = "page" in request.GET if is_get and not is_pagination: # Push the current path unless overridden response.headers["HX-Push-Url"] = self.htmx_push_url or request.get_full_path() print(response.headers) if self.htmx_trigger: response.headers["HX-Trigger"] = self.htmx_trigger if self.htmx_trigger_after_settle: response.headers["HX-Trigger-After-Settle"] = self.htmx_trigger_after_settle if self.htmx_trigger_after_swap: response.headers["HX-Trigger-After-Swap"] = self.htmx_trigger_after_swap return response def render_to_response(self, context, **response_kwargs): """Renders HTMX response, applying headers and handling directives""" request = self.request if not request.htmx: response = super().render_to_response(context, **response_kwargs) return self.apply_htmx_headers(response) if self.htmx_redirect_url: return HttpResponseClientRedirect(self.htmx_redirect_url) if self.htmx_refresh: return HttpResponseClientRefresh() html = self.render_partial(context) response = HttpResponse(html, **response_kwargs) return self.apply_htmx_headers(response)