Using Forms
HXRequests
with is forms. HXRequests
gives a simple way to post data and update the page asyncronously.FormHXRequest
the form is fetched asyncronously using the GET_template
, the form is saved and then it returns the POST_template
Basic Form
Form
from django import forms
class UserInfoForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
HTML
user_info_page.html
{% load hx_tags %}
<div id="user_info">
{% include 'user_info.html' %}
</div>
<form method="post">
<div hx-trigger='load'
{% hx_get 'user_info_form' object=request.user %}>
</div>
<button type="submit"
hx-target="#user_info"
{% hx_post 'user_info_form' object=request.user %}>
Submit
</button>
</form>
user_info.html
{{ user.email }}
{{ user.first_name }}
{{ user.last_name }}
- Notes:
‘user_info_form’ in the template tags is the name of the
HXRequest
that these requests will be routed to (see below)object
is equivalent to an instance in a Django form. In theget
it’s used to set the initial of the fields. In thepost
it’s the object that is getting updated.An
include
is used so that it can be reused below as thePOST_template
in theHXRequest
.The user in
user_info.html
comes from the context of the view.
Tip
includes
are very helpful when using htmx, because it gives an easy way to load part of the html.
HXRequest
from hx_requests.hx_requests import FormHXRequest
class UserInfoHXRequest(FormHXRequest):
name = "user_info_form"
form_class = UserInfoForm
GET_template = 'form.html' # Renders the form
POST_template = 'user_info.html' # The 'include' in the HTML above
hx_object_name = "user"
def form_valid(self,**kwargs):
# This is the default form_valid
self.form.save()
return self.get_response(**kwargs)
def form_invalid(self, **kwargs) -> str:
# This is the default form_invalid
return self.get_response(**kwargs)
- Notes:
form_valid
by default callsform.save()
and returns thePOST_template
form_invalid
by default returns theGET_template
. The purpose of this is to show the error messages. Becauseis_valid
was called (is_valid
is called in thepost
method), the form now contains the errors, which gives you asyncronous validation of the form.The
GET_template
(form.html) has access to the form as ‘form’ in the contexthx_object_name
is the name given to the object when it’s passed into the context. Above inuser_info.html
(thePOST_template
), onPOST
the user in that context is the object that was passed in to thehx_post
template tag (although now it was updated by the form). Ifhx_object_name
was not set, instead of referencing the object as ‘user’ inuser_info.html
, it would be referenced ashx_object
(i.e.hx_object.username
)The object is saved as an attribute on the
HXRequest
ashx_object
, so it can be referenced anywhere in the class asself.hx_object
Setting Form Kwargs
get_form_kwargs
.get_initial
.from hx_requests.hx_requests import FormHXRequest
class MyHXRequest(FormHXRequest):
# Set attributes
def get_form_kwargs(self,**kwargs):
kwargs = super().get_form_kwargs(**kwargs)
# Add the user to the form
kwargs['user'] = self.request.user
return kwargs
def get_initial(**kwargs):
initial = super().get_initial(**kwargs)
# Set the initial value of 'created_by' field
initial['created_by'] = self.request.user
return initial
You can also set the initial from the kwargs by setting set_initial_from_kwargs
to True
.
This setting allows the initial value to be automatically populated from the kwargs.
As long as the key in the kwargs matches the name of a field in the form, it will be assigned as the initial value for that field.
from hx_requests.hx_requests import FormHXRequest
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['field1', 'field2']
class MyHXRequest(FormHXRequest):
name='my_hx_request'
set_initial_from_kwargs = True
<button {% hx_get 'my_hx_request' field1="Cool Initial Value" %}></button>
- Notes:
The initial value of
field1
will be set to"Cool Initial Value"
Setting Messages
Note
See Messages for more details and for config settings.
In a FormHXRequest
success and error messages can be set by overriding get_success_message
and get_error_message
class MyHXRequest(FormHXRequest):
# Set attributes
def get_success_message(self, **kwargs) -> str:
# This is not the default
return "Form saved sucessfully"
def get_error_message(self, **kwargs) -> str:
# This is not the default
return "Did not save due to errors in the form"
- Notes:
Set
add_form_errors_to_error_message
toTrue
to add the form errors to the error message automatically. But then do not overrideget_error_message
.
Note
Messages can be set in any HXRequest
at any point like this:
self.messages.success("Hooray!")
Message types are: debug, info, succes s, warning and error.
Forms in Modals
See Form Modals