Plain is headed towards 1.0! Subscribe for development updates →

 1from plain.utils.cache import patch_vary_headers
 2
 3from .templates import render_template_fragment
 4
 5
 6class HTMXViewMixin:
 7    def render_template(self):
 8        template = self.get_template()
 9        context = self.get_template_context()
10
11        if self.is_htmx_request() and self.get_htmx_fragment_name():
12            return render_template_fragment(
13                template=template._jinja_template,
14                fragment_name=self.get_htmx_fragment_name(),
15                context=context,
16            )
17
18        return template.render(context)
19
20    def get_response(self):
21        response = super().get_response()
22        # Tell browser caching to also consider the fragment header,
23        # not just the url/cookie.
24        patch_vary_headers(
25            response, ["HX-Request", "Plain-HX-Fragment", "Plain-HX-Action"]
26        )
27        return response
28
29    def get_request_handler(self):
30        if self.is_htmx_request():
31            # You can use an htmx_{method} method on views
32            # (or htmx_{method}_{action} for specific actions)
33            method = f"htmx_{self.request.method.lower()}"
34
35            if action := self.get_htmx_action_name():
36                # If an action is specified, we throw an error if
37                # the associated method isn't found
38                return getattr(self, f"{method}_{action}")
39
40            if handler := getattr(self, method, None):
41                # If it's just an htmx post, for example,
42                # we can use a custom method or we can let it fall back
43                # to a regular post method if it's not found
44                return handler
45
46        return super().get_request_handler()
47
48    def is_htmx_request(self):
49        return self.request.headers.get("HX-Request") == "true"
50
51    def get_htmx_fragment_name(self):
52        # A custom header that we pass with the {% htmxfragment %} tag
53        return self.request.headers.get("Plain-HX-Fragment", "")
54
55    def get_htmx_action_name(self):
56        return self.request.headers.get("Plain-HX-Action", "")