The idea of hx-requests is that HXRequests
absorb all htmx requests.
Define an HXRequest
(we'll get into how to do that in just a sec) and
observe the magic of hx-requests
.
- No need to define extra urls to handle these requests
- No need to add anything extra in views
- Reusable
HXRequests
across views - Built in
HXReuqests
to reduce boilerplate code (Forms, Deleting, Modals)
The view requires HtmxViewMixin
from hx_requests.views import HtmxViewMixin
from django.views.generic.base import View
class MyView(HtmxViewMixin, View):
pass
{% load hx_tags %}
<div id="user_info_target"></div>
<button {% hx_get 'get_user_info' %}
hx-target="#user_info_target"
type="button">
Click Me
</button>
- Notes:
- Using the :ref:`hx_get <hx_get>` template tag signifies that it's an
hx-get
- 'get_user_info' is the name of this
HXRequest
. See below to understand what that means - The goal of this
hx-get
is to render a user info card into the empty div
- Using the :ref:`hx_get <hx_get>` template tag signifies that it's an
Create an hx_requests.py
file
Warning
All HXRequests
must be defined inside an hx_requests.py
file, and the hx_requests.py
files must live inside an app that's included in Django's INSTALLED_APPS
.
hx-get
will get directed to this HXRequest
.from hx_requests.hx_requests import BaseHXRequest
class GetUserInfo(BaseHXRequest):
name = "get_user_info"
GET_template = "user_info_card.html"
- Notes:
GetUserInfo
will return the HTML from theGET_template
(user_info_card.html
)
user_info_card.html
<div>
<p>Username:{{request.user.username}}</p>
<p>Email:{{request.user.email}}</p>
</div>
HXRequest
that matches the name (1st argument) passed into the hx_get
template tag. In this example 'get_user_info'. That's how the hx-get
is routed to GetUserInfo
.GET_template
.Note
The GET_template
has access to all of the context that is in the view.
Alomost exactly the same as the GET
request above.
Note
Working with a form? See :ref:`Using Forms`
The view requires HtmxViewMixin
from hx_requests.views import HtmxViewMixin
from django.views.generic.base import View
class MyView(HtmxViewMixin, View):
pass
{% load hx_tags %}
<div id="email_display">{{request.user.email}}</div>
<input type="text" name="email" id='email_input'/>
<button {% hx_post 'change_email' %}
hx-target="#email_display"
hx-include="#email_input"
type="button">
Save
</button>
- Notes:
- Using the :ref:`hx_post <hx_post>` template tag signifies that it's an
hx-post
- The goal of this
hx-post
is to change the signed in user's email to the value of the input replace the email address in the div with the updated email
- Using the :ref:`hx_post <hx_post>` template tag signifies that it's an
Create an hx_requests.py
file
Warning
All HXRequests
must be defined inside an hx_requests.py
file, and the hx_requests.py
files must live inside an app that's included in Django's INSTALLED_APPS
.
hx-post
will get directed to this HXRequest
.from hx_requests.hx_requests import BaseHXRequest
class ChangeEmail(BaseHXRequest):
name = "change_email"
POST_template = "email.html"
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
user = request.user
user.email = request.POST.get("email")
user.save()
return super().post(request, *args, **kwargs)
- Notes:
ChangeEmail
will return the HTML from thePOST_template
(email.html
)
email.html
<span>{{request.user.email}}</span>
HXRequest
that matches the name (1st argument) passed into the hx_post
template tag. In this example 'change_email'. That's how the hx-post
is routed to ChangeEmail
.POST_template
.Note
The POST_template
has access to all of the context that is in the view.
Many times you may need additional context in the GET_template
or POST_template
. Luckily, there is
a simple way to add context to them.
from hx_requests.hx_requests import BaseHXRequest
class MyHXRequest(BaseHXRequest):
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["important_var"] = "I am important"
return context
Additionally, if you only want the contex added on post (i.e. you want one of the form values in the POST_template
), you can
instead override get_post_context_data
from hx_requests.hx_requests import BaseHXRequest
class MyHXRequest(BaseHXRequest):
...
def get_post_context_data(self, **kwargs):
context = super().get_post_context_data(**kwargs)
context["important_var"] = "I am important"
return context
Note
The GET_template
and the POST_template
have access to hx_obect
(or the name it's given by setting hx_object_name
)
and the kwargs passed into hx_get
or hx_post
.
For example:
{% hx_get 'my_hx_request' object=object my_awesome_kwarg="I am awesome" %}
In the GET_template
, 'my_awesome_kwarg' can be accessed as my_awesome_kwarg
unless kwargs_as_context
is set to False then it can be accessed as {{ hx_kwargs.my_awesome_kwarg }}
One key feature of hx-requests
is that the HxRequest
class grants access to the context of the view it is associated with.
However, a common issue arises when the view sets up attributes within its get
method that the context relies on.
This poses a challenge because HXRequest
does not directly invoke the view's get
method, potentially resulting in an error where
self.{var}
is inaccessible.
To mitigate this issue, hx-requests
automatically resolves Django's views and invokes the get
method on your behalf.
Notably, it does so without returning the response immediately. This approach minimizes performance overhead,
as returning the response entails the view evaluating the entire response, which can be detrimental to performance.
Additionally, hx-requests
offers the flexibility to configure get
behavior for custom views through settings,
as detailed in the :ref:`settings <Configuration>`.
Example of the get for a UpdateView
:
def update_view_get(self, request, *args, **kwargs):
self.object = self.get_object()
- Notes:
UpdateView
relys on the get setting theself.object
attribute.hx-requests
will call theget
method and set theself.object
attribute for you.- The function takes the same arguments as the
get
method of the view.
Example of setting up a custom view's get:
def my_custom_view_get(self, request, *args, **kwargs):
self.my_custom_attribute = "I am custom"
# In settings.py
HX_REQUESTS_CUSTOM_VIEWS_SETUP = {
'my_app.views.my_custom_view' : 'my_app.view_get_functions.custom_view_get',
}
Note
A good example of a use case is if you are using django-filters. The FilterView
sets up attributes in the get
method
and also passes them to the context. To use FilterView
with hx-requests
, you would need to setup the get
method
to match the get
method of the FilterView
and return the extra context instead of the response.
def filter_view_get(self,request,*args,**kwargs):
filterset_class = self.get_filterset_class()
self.filterset = self.get_filterset(filterset_class)
if (
not self.filterset.is_bound
or self.filterset.is_valid()
or not self.get_strict()
):
self.object_list = self.filterset.qs
else:
self.object_list = self.filterset.queryset.none()
# Return the extra context
return {'filter': self.filterset, 'object_list': self.object_list}