## Упрощение динамической веб-разработки с [[Django]] и HTMX: использование форм и сериализаторов {#sec-b233da7ff7c9} В предыдущей статье мы рассмотрели, **как [[HTMX]] передает данные на сервер**. **См. предыдущую статью**: [Упрощение динамической веб-разработки с Django и HTMX (Часть 4): Методы передачи полезной нагрузки](/ko/whitedec/2025/1/27/django-htmx-csrf-token-integration/) Мы убедились, что если функция `fetch()` в традиционном JavaScript напрямую создает и отправляет JSON-полезную нагрузку, то **HTMX больше ориентирован на сбор значений из DOM и их отправку в виде form-data**. Тогда, естественно, возникает вопрос: **"Какой способ валидации данных, полученных через HTMX, наиболее естественен в Django?"** Многие поначалу могут подумать о **DRF Serializer**. Действительно, сериализатор — мощный инструмент валидации, который можно использовать не только с JSON. Однако при работе с HTMX он иногда может казаться несколько натянутым. Почему так происходит? Причина проста: **Основной подход HTMX ближе к миру HTML-форм, а в Django уже есть `Form`, разработанный специально для этого мира.** В этой статье мы рассмотрим, **как можно использовать `Django Form` и `DRF Serializer` при обработке HTMX-запросов**, а также **какой из них является более естественным и практичным выбором**. ![Сравнение ролей Form и Serializer при обработке HTMX-запросов](/media/whitedec/blog_img/06d08ad8294d4067af3a9001566ddf5a.webp) --- ## Данные, отправляемые [[HTMX]], по сути, являются "данными формы" {#sec-8c911eee119a} Как мы видели в предыдущей части, HTMX по умолчанию собирает значения HTML-элементов и отправляет их на сервер. Это может быть отправка входных значений внутри `
`, включение определенных элементов с помощью `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 подходит лучше {#sec-b1e7f36e5f83} DRF Serializer, безусловно, отличный инструмент. Однако, если учитывать его первоначальный контекст проектирования, сериализатор больше ориентирован на **сериализацию данных и валидацию ввода API**. В то время как Django Form изначально был создан для следующего: * Обработка ввода HTML-форм * Валидация на стороне сервера * Отображение сообщений об ошибках * Сохранение введенных значений * Перерисовка шаблонов То есть, он гораздо естественнее сочетается с подходом, подобным HTMX, когда **"получается и заменяется часть HTML"**. Рассмотрим пример. Пользователь отправляет форму для написания комментария. * Что, если валидация не удалась? * Введенные данные должны быть сохранены * Необходимо показать, какое поле содержит ошибку * Форма с ошибками должна быть частично перерисована Django Form отлично справляется с таким пользовательским опытом. Конечно, Serializer также предоставляет `errors` и позволяет выполнять валидацию. Однако следующий шаг — **"перестройка всего пользовательского интерфейса HTML-формы"** — гораздо более гладко реализуется с помощью Form. Поэтому, если рассматривать только совместимость с HTMX, правильнее считать Form основным выбором. --- ## Наиболее естественное сочетание: [[HTMX]] + Django Form {#sec-23fc963f6963} Сначала рассмотрим самый простой пример. Это простая форма для регистрации задачи. ### Определение формы {#sec-fba81a38a40a} ```python 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 для валидации. ### Обработка в представлении {#sec-568150151637} ```python 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, }) ``` Здесь суть очень ясна: 1. **Значения, отправленные HTMX, принимаются через `request.POST`** 2. **Форма выполняет валидацию** 3. **В случае успеха возвращается HTML-фрагмент** 4. **В случае неудачи форма с ошибками перерисовывается** Этот подход соответствует духу Django и HTMX, и, что самое главное, он прост в обслуживании. --- ## Естественное отображение ошибок в шаблоне {#sec-18af3291951b} Именно здесь Django Form проявляет себя особенно ярко. При сбое валидации объект Form уже содержит следующую информацию: * Значения, введенные пользователем * Сообщения об ошибках для каждого поля * Ошибки, не связанные с полями * Статус валидности каждого поля Следовательно, в частичном шаблоне их можно просто отрендерить. ### `todo_form.html` {#sec-8a4853cf4018} ```html {% csrf_token %} {% if form.non_field_errors %}
{{ form.non_field_errors }}
{% endif %}
{{ form.title }} {% if form.title.errors %}
{{ form.title.errors }}
{% endif %}
{{ form.priority }} {% if form.priority.errors %}
{{ form.priority.errors }}
{% endif %}
``` Этот пример очень прост, но хорошо демонстрирует совместимость [[HTMX]] и Django Form. * При сбое можно перерисовать всю форму * Введенные пользователем значения сохраняются * Сообщения об ошибках естественно отображаются рядом с полями При использовании традиционного подхода `fetch()` + JSON + ручное манипулирование DOM потребовалось бы значительно больше JavaScript для реализации такого потока. Однако в сочетании HTMX и Django Form это можно обработать гораздо проще, используя только серверный код и шаблоны. --- ## Значит ли это, что сериализаторы не нужны? {#sec-5f0d93fcd48a} Утверждение, что **сериализаторы не нужны**, кажется слишком категоричным. Возможно, лучше выразиться так: **Нет необходимости выбирать сериализатор в качестве основного инструмента по умолчанию.** На самом деле, [[DRF]] Serializer по-прежнему очень привлекателен в следующих ситуациях: * Если DRF уже активно используется в проекте * Если необходимо повторно использовать одну и ту же логику валидации для API и серверных страниц * Если логика валидации ввода сложна и уже хорошо структурирована в Serializer * Если планируется в будущем предоставить ту же функциональность для мобильных приложений или внешних API То есть, вопрос не в том, **"можно ли использовать Serializer с HTMX?"**, а скорее в том, **"есть ли архитектурная выгода в использовании Serializer именно здесь?"** --- ## Сериализатор также можно использовать {#sec-bfbe9c61b12c} Например, предположим, у нас уже есть такой сериализатор: ```python 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-запросов. ```python 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 при совместном использовании может казаться немного натянутым. --- ## Заключение {#sec-37e5d418cdb7} В предыдущей части мы рассмотрели, как [[HTMX]] отправляет данные. А в этой части мы обобщили, какой способ валидации этих данных в Django является наиболее естественным. * HTMX по умолчанию хорошо сочетается с form-data * Django Form — это инструмент, разработанный специально для этого процесса * Поэтому, с точки зрения совместимости с HTMX, Form является наиболее естественным выбором * DRF Serializer можно использовать, но это скорее стратегический выбор Лично я считаю, что для эффективного использования HTMX необходимо восстановить не только **"чувство работы с AJAX в стиле HTML"**, но и **"чувство использования Django Form и тегов форм"**. --- **Читайте также** * [Упрощение динамической веб-разработки с Django и HTMX (Часть 1)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification/) * [Упрощение динамической веб-разработки с Django и HTMX - Ajax (Часть 2)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-2/) * [Упрощение динамической веб-разработки с Django и HTMX (Часть 3): Методы интеграции с Django](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-3/) * [Упрощение динамической веб-разработки с Django и HTMX (Часть 4): Как передавать полезную нагрузку?](/ko/whitedec/2025/1/27/django-htmx-advanced-features/)