POST requests (or anything that isn’t GET or HEAD) require some care due to CSRF protection.
The simplest approach involves creating a form as normal and including the {%
csrf_token %} template tag.
<h1>Make some monsters!</h1>
<form>
{% csrf_token %}
How many: <input type="number" name="howmany" value="1">
<button
hx-post="{% url 'post_form_endpoint' %}"
hx-trigger="click"
hx-target="#monsters-created"
hx-swap="beforeend"
>Make some!
</button>
</form>In this case the whole of the form, including the CSRF token and other
parameters like howmany, get submitted as part of the POST request, and you
will have no problems.
Note that the normal pattern of POST/redirect/GET, which is needed to avoid problems with page refresh and form re-submission, is not needed in this case as the POST request doesn’t return a full page.
However, in many cases it will be inconvenient to use a form, or you may want to
use controls that wouldn’t normally submit other values, such as links. An easy
solution is to put the token into custom htmx headers, by adding hx-headers
into the <body> element, usually in a base.html template:
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>Example view code, template, base template
If it is awkward to put this into the <body> element in a base template (because you are using a base template that you can’t modify, for example), another technique that works is to add a <script> somewhere in an overridden base template to set the hx-headers attribute using Javascript, like this:
<script>
document.body.setAttribute('hx-headers', '{"X-CSRFToken": "{{ csrf_token }}"}');
</script>There are other options, like hooking into htmx:beforeRequest and adding Javascript code described in the Django CSRF docs