Упрощение динамической веб-разработки с Django и HTMX: использование форм и сериализаторов
В предыдущей статье мы рассмотрели, как HTMX передает данные на сервер.
См. предыдущую статью: Упрощение динамической веб-разработки с Django и HTMX (Часть 4): Способы передачи полезной нагрузки (Payload)
Мы убедились, что если функция fetch() в традиционном JavaScript напрямую создает и отправляет JSON-полезную нагрузку, то HTMX больше ориентирован на сбор значений из DOM и их отправку в виде form-data.
Тогда, естественно, возникает вопрос:
"Какой способ валидации данных, полученных через HTMX, наиболее естественен в Django?"
Многие поначалу могут подумать о DRF Serializer. Действительно, сериализатор — мощный инструмент валидации, который можно использовать не только с JSON. Однако при работе с HTMX он иногда может казаться несколько натянутым.
Почему так происходит?
Причина проста:
Основной подход HTMX ближе к миру HTML-форм, а в Django уже есть Form, разработанный специально для этого мира.
В этой статье мы рассмотрим, как можно использовать Django Form и DRF Serializer при обработке HTMX-запросов, а также какой из них является более естественным и практичным выбором.

Данные, отправляемые HTMX, по сути, являются "данными формы"
Как мы видели в предыдущей части, HTMX по умолчанию собирает значения HTML-элементов и отправляет их на сервер. Это может быть отправка входных значений внутри <form>, включение определенных элементов с помощью hx-include или добавление дополнительных значений с помощью hx-vals.
Таким образом, основная философия HTMX ближе к следующему:
- Не собирает JavaScript-объекты напрямую
- Собирает значения из HTML-элементов
- Отправляет запрос на сервер
- Лучше сочетается с ответами в виде HTML-фрагментов, чем с JSON
Этот подход гораздо важнее, чем кажется, поскольку его структура почти полностью совпадает с типичным процессом обработки форм в Django.
Django Form также разработан с учетом следующих предположений:
- Пользователь вводит данные в HTML-форму
- Сервер получает
request.POST - Форма валидирует данные
- При наличии ошибок форма перерисовывается
- При отсутствии проблем данные сохраняются, и отправляется ответ
К этому моменту начинает казаться, что HTMX и Django Form идеально подходят друг другу, как Золушка и хрустальная туфелька.
Поэтому, возможно, стоит сделать такой вывод:
Самый естественный инструмент валидации в Django, который идеально сочетается с HTMX, — это Django Form, а не DRF Serializer.
Почему Django Form подходит лучше
DRF Serializer, безусловно, отличный инструмент. Однако, если учитывать его первоначальный контекст проектирования, сериализатор больше ориентирован на сериализацию данных и валидацию ввода API.
В то время как Django Form изначально был создан для следующего:
- Обработка ввода HTML-форм
- Валидация на стороне сервера
- Отображение сообщений об ошибках
- Сохранение введенных значений
- Перерисовка шаблонов
То есть, он гораздо естественнее сочетается с подходом, подобным HTMX, когда "получается и заменяется часть HTML".
Рассмотрим пример.
Пользователь отправляет форму для написания комментария.
- Что, если валидация не удалась?
- Введенные данные должны быть сохранены
- Необходимо показать, какое поле содержит ошибку
- Форма с ошибками должна быть частично перерисована
Django Form отлично справляется с таким пользовательским опытом.
Конечно, Serializer также предоставляет errors и позволяет выполнять валидацию. Однако следующий шаг — "перестройка всего пользовательского интерфейса HTML-формы" — гораздо более гладко реализуется с помощью Form.
Поэтому, если рассматривать только совместимость с HTMX, правильнее считать Form основным выбором.
Наиболее естественное сочетание: HTMX + Django Form
Сначала рассмотрим самый простой пример. Это простая форма для регистрации задачи.
Определение формы
from django import forms
class TodoForm(forms.Form):
title = forms.CharField(max_length=100, label="제목")
priority = forms.IntegerField(min_value=1, max_value=5, label="우선순위")
Теперь в представлении можно просто передать request.POST в Form для валидации.
Обработка в представлении
from django.shortcuts import render
from django.http import HttpResponse
def todo_create(request):
if request.method == "POST":
form = TodoForm(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
priority = form.cleaned_data["priority"]
# 로직 수행 (예: сохранение задачи)
# Todo.objects.create(title=title, priority=priority)
return render(request, "todos/partials/todo_item.html", {
"title": title,
"priority": priority,
})
return render(request, "todos/partials/todo_form.html", {
"form": form,
}, status=400)
form = TodoForm()
return render(request, "todos/partials/todo_form.html", {
"form": form,
})
Здесь суть очень ясна:
- Значения, отправленные HTMX, принимаются через
request.POST - Форма выполняет валидацию
- В случае успеха возвращается HTML-фрагмент
- В случае неудачи форма с ошибками перерисовывается
Этот подход соответствует духу Django и HTMX, и, что самое главное, он прост в обслуживании.
Естественное отображение ошибок в шаблоне
Именно здесь Django Form проявляет себя особенно ярко.
При сбое валидации объект Form уже содержит следующую информацию:
- Значения, введенные пользователем
- Сообщения об ошибках для каждого поля
- Ошибки, не связанные с полями
- Статус валидности каждого поля
Следовательно, в частичном шаблоне их можно просто отрендерить.
todo_form.html
<form hx-post="{% url 'todo_create' %}" hx-target="#todo-form-wrap" hx-swap="outerHTML">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="error-box">
{{ form.non_field_errors }}
</div>
{% endif %}
<div>
<label for="{{ form.title.id_for_label }}">제목</label>
{{ form.title }}
{% if form.title.errors %}
<div class="field-error">{{ form.title.errors }}</div>
{% endif %}
</div>
<div>
<label for="{{ form.priority.id_for_label }}">우선순위</label>
{{ form.priority }}
{% if form.priority.errors %}
<div class="field-error">{{ form.priority.errors }}</div>
{% endif %}
</div>
<button type="submit">등록</button>
</form>
Этот пример очень прост, но хорошо демонстрирует совместимость HTMX и Django Form.
- При сбое можно перерисовать всю форму
- Введенные пользователем значения сохраняются
- Сообщения об ошибках естественно отображаются рядом с полями
При использовании традиционного подхода fetch() + JSON + ручное манипулирование DOM потребовалось бы значительно больше JavaScript для реализации такого потока. Однако в сочетании HTMX и Django Form это можно обработать гораздо проще, используя только серверный код и шаблоны.
Значит ли это, что сериализаторы не нужны?
Утверждение, что сериализаторы не нужны, кажется слишком категоричным. Возможно, лучше выразиться так: Нет необходимости выбирать сериализатор в качестве основного инструмента по умолчанию.
На самом деле, DRF Serializer по-прежнему очень привлекателен в следующих ситуациях:
- Если DRF уже активно используется в проекте
- Если необходимо повторно использовать одну и ту же логику валидации для API и серверных страниц
- Если логика валидации ввода сложна и уже хорошо структурирована в Serializer
- Если планируется в будущем предоставить ту же функциональность для мобильных приложений или внешних API
То есть, вопрос не в том, "можно ли использовать Serializer с HTMX?", а скорее в том, "есть ли архитектурная выгода в использовании Serializer именно здесь?"
Сериализатор также можно использовать
Например, предположим, у нас уже есть такой сериализатор:
from rest_framework import serializers
class TodoSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
priority = serializers.IntegerField(min_value=1, max_value=5)
В этом случае его вполне можно использовать и для HTMX-запросов.
from django.shortcuts import render
def todo_create_with_serializer(request):
if request.method == "POST":
serializer = TodoSerializer(data=request.POST)
if serializer.is_valid():
title = serializer.validated_data["title"]
priority = serializer.validated_data["priority"]
return render(request, "todos/partials/todo_item.html", {
"title": title,
"priority": priority,
})
return render(request, "todos/partials/todo_form_serializer.html", {
"errors": serializer.errors,
"data": request.POST,
}, status=400)
Как видите, технически проблем нет никаких. Сериализатор не является инструментом, предназначенным только для JSON.
Однако здесь проявляется тонкое различие.
При использовании Form:
- Сохранение введенных значений
- Рендеринг полей
- Привязка ошибок
- Связь с шаблоном
Все это происходит естественным образом.
В то время как при использовании Serializer:
- Необходимо вручную адаптировать
serializer.errorsк структуре шаблона - Передавать существующие входные значения отдельно
- Разработчику приходится больше заботиться о связи с перерисовкой HTML-формы
То есть, использовать его можно, но это требует немного больше ручной работы.
Именно из-за этого момента HTMX и Serializer при совместном использовании может казаться немного натянутым.
Заключение
В предыдущей части мы рассмотрели, как HTMX отправляет данные. А в этой части мы обобщили, какой способ валидации этих данных в Django является наиболее естественным.
- HTMX по умолчанию хорошо сочетается с form-data
- Django Form — это инструмент, разработанный специально для этого процесса
- Поэтому, с точки зрения совместимости с HTMX, Form является наиболее естественным выбором
- DRF Serializer можно использовать, но это скорее стратегический выбор
Лично я считаю, что для эффективного использования HTMX необходимо восстановить не только "чувство работы с AJAX в стиле HTML", но и "чувство использования Django Form и тегов форм".
Читайте также
Комментариев нет.