Упрощение динамической веб-разработки с Django и HTMX (Часть 4): Как передавать данные (payload)?
При использовании fetch для Ajax-запросов в традиционном JavaScript для отправки POST-запросов обычно формируют полезную нагрузку (payload) вручную, используя JSON.stringify().
Примерно так:
fetch("/api/todos/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken
},
body: JSON.stringify({
title: "장보기",
done: false,
priority: 3
})
})
А что насчет HTMX? Как hx-post отправляет данные на сервер? Многие примеры демонстрируют лишь очень простые функции, поэтому найти практические примеры отправки сложной полезной нагрузки на удивление сложно.
В этом посте мы полностью разберем методы передачи данных в HTMX и способы их обработки на сервере.

Методы передачи данных в HTMX
Подход к полезной нагрузке в fetch и методы передачи данных в hx-post значительно различаются.
В fetch разработчик создает объект напрямую и преобразует его в JSON для помещения в тело запроса. В отличие от этого, HTMX по умолчанию собирает и отправляет значения из DOM.
Философия HTMX ближе не к "прямому формированию JS-объектов", а к "сбору значений из HTML-элементов для формирования параметров запроса". Для этого обычно используются следующие три способа:
1) Сбор и отправка значений на основе формы
Это наиболее HTML-ориентированный способ, который хорошо подходит для Django.
<form hx-post="/todos/create/" hx-target="#todo-list">
<input type="text" name="title" placeholder="제목">
<input type="number" name="priority" value="3">
<input type="hidden" name="done" value="false">
<button type="submit">등록</button>
</form>
В этом случае HTMX собирает значения полей ввода внутри формы и включает их в запрос. Стандартное кодирование — это URL-encoded form data, как при обычной отправке формы.
В представлении Django вы можете получить их как обычно:
def create_todo(request):
title = request.POST.get("title")
priority = request.POST.get("priority")
done = request.POST.get("done")
2) Включение значений из других элементов без формы: hx-include
Используется, когда вы хотите прикрепить hx-post к одной кнопке, но выборочно отправить значения из удаленных полей ввода.
<input type="text" id="title" name="title" placeholder="제목">
<input type="number" id="priority" name="priority" value="3">
<button hx-post="/todos/create/"
hx-include="#title, #priority"
hx-target="#todo-list">
등록
</button>
hx-include включает значения указанных элементов в запрос. Это очень удобно, когда полей ввода немного, так как позволяет получить результат, похожий на полезную нагрузку, без необходимости оборачивать все в <form>.
3) Добавление скрытых или вычисляемых значений: hx-vals
Эта функция наиболее близка к концепции прямого создания части объекта полезной нагрузки в fetch.
<button hx-post="/todos/create/"
hx-vals='{"title": "장보기", "done": false, "priority": 3}'
hx-target="#todo-list">
빠른 등록
</button>
hx-vals добавляет дополнительные параметры к запросу. По умолчанию используется синтаксис JSON, как показано выше, но если добавить префикс js:, можно отправлять динамически вычисляемые значения JavaScript.
<input type="text" id="title" placeholder="제목">
<button hx-post="/todos/create/"
hx-vals='js:{title: document.querySelector("#title").value, done: false, priority: 3}'
hx-target="#todo-list">
등록
</button>
В этом случае Django также считывает данные через request.POST. Это потому, что hx-vals определяет значения с использованием синтаксиса, похожего на JSON, но не преобразует сам текст запроса в JSON.
Важное замечание: hx-vals отличается от "JSON Payload"
Это наиболее запутанный момент для тех, кто впервые сталкивается с HTMX.
<button hx-post="/my-url/" hx-vals='{"a":1, "b":2}'>
Этот код означает не "отправить JSON-объект в теле запроса", а скорее добавить a=1&b=2 к параметрам запроса. То есть, на сервере по-прежнему нужно обрабатывать данные как данные формы.
Что если вы действительно хотите отправить JSON-тело?
Если вам обязательно нужен формат application/json, как в fetch(... JSON.stringify(payload)), то потребуется расширение json-enc для HTMX.
Следуйте инструкциям в официальной документации для настройки:
<script src="https://unpkg.com/htmx.org@1.9.12/dist/ext/json-enc.js"></script>
<button hx-post="/api/todos/"
hx-ext="json-enc"
hx-vals='{"title": "장보기", "done": false, "priority": 3}'
hx-target="#result">
JSON으로 전송
</button>
Теперь это становится привычным нам способом передачи JSON-полезной нагрузки. В этом случае в представлении Django request.POST будет пустым, поэтому вам придется читать request.body напрямую.
import json
def create_todo_api(request):
data = json.loads(request.body)
title = data.get("title")
# ... Логика обработки ...
return JsonResponse({"ok": True})
HTMX и DRF имеют разные философии, но не обязательно должны быть объединены.
Хотя можно отправлять JSON с помощью расширений, остается вопрос, является ли это истинным способом HTMX. Это связано с тем, что здесь сталкиваются две философии: "ориентированная на данные (DRF)" и "ориентированная на гипермедиа (HTMX)".
Если вы решили использовать HTMX по назначению, возможно, стоит на время отойти от мышления, ориентированного на данные. Отправка значений с помощью <form>, hx-include, hx-vals и получение сервером этих данных через request.POST с возвратом HTML-фрагментов, а не JSON, — именно в этом HTMX проявляет себя наилучшим образом.
Но что, если сериализаторы DRF слишком ценны, чтобы от них отказываться?
Сериализаторы DRF действительно мощны. Означает ли использование HTMX, что мы должны отказаться от этого удобного инструмента валидации и заниматься рутиной request.POST.get()?
К счастью, сериализаторы DRF прекрасно валидируют не только JSON, но и данные форм. Эта тема довольно обширна, поэтому в следующей части мы подробно рассмотрим "Совместное существование HTMX и сериализаторов DRF".
Заключение
Подведем итоги сегодняшнего материала:
- HTMX по умолчанию собирает значения из DOM. Его подход отличается от
fetch, который требует прямого создания объекта полезной нагрузки. - Три способа передачи данных:
<form>для отправки всего,hx-includeдля выборочной отправки иhx-valsдля добавления значений. - По умолчанию используется формат данных формы. Будьте внимательны: хотя
hx-valsиспользует синтаксис JSON, это не означает, что он отправляет JSON-тело запроса. - Если JSON абсолютно необходим, используйте расширение
json-enc. Однако помните, что истинная прелесть HTMX заключается в обмене HTML-фрагментами.
В следующий раз мы вернемся к тому, как интегрировать удобство DRF в HTMX!
Связанные статьи:
- Упрощение динамической веб-разработки с Django и HTMX (Часть 1)
- Упрощение динамической веб-разработки с Django и HTMX - Ajax (Часть 2)
- Упрощение динамической веб-разработки с Django и HTMX (Часть 3): Методы интеграции с Django
- Упрощение динамической веб-разработки с Django и HTMX (Часть 4): Способы передачи полезной нагрузки (Payload)
- Упрощение динамической веб-разработки с Django и HTMX: использование форм и сериализаторов
- Упрощение динамической веб-разработки с Django и HTMX: Использование триггеров