## Simplificando el desarrollo web dinámico con [[Django]] y HTMX: Uso de Forms y Serializers {#sec-b233da7ff7c9} En el artículo anterior, examinamos **cómo [[HTMX]] transmite datos al servidor**. **Ver artículo anterior**: [Simplificando el desarrollo web dinámico con Django y HTMX (Parte 4): Métodos de envío de payload](/ko/whitedec/2025/1/27/django-htmx-csrf-token-integration/) Confirmamos que, mientras que el `fetch()` de JavaScript se acerca más a la creación y envío directo de un payload JSON, **HTMX se asemeja más a la recopilación de valores del DOM para enviarlos como datos de formulario**. Esto nos lleva naturalmente a la siguiente pregunta: **"¿Cuál es la forma más natural de validar los datos recibidos por HTMX en Django?"** Inicialmente, muchos podrían pensar en el **DRF Serializer**. De hecho, un Serializer es una potente herramienta de validación y puede usarse incluso sin JSON. Sin embargo, al probarlo con HTMX, a veces puede sentirse un poco forzado. ¿Por qué? La razón es simple: **El flujo básico de HTMX está más alineado con el mundo de los formularios HTML, y Django ya cuenta con `Form`s diseñados precisamente para ese propósito.** En este artículo, analizaremos **cómo se pueden utilizar `Django Form`s y `DRF Serializer`s para procesar solicitudes HTMX**, y **cuál de ellos es la opción más natural y práctica**. ![Comparación del rol de Form y Serializer en el procesamiento de solicitudes HTMX](/media/whitedec/blog_img/06d08ad8294d4067af3a9001566ddf5a.webp) --- ## Los datos enviados por [[HTMX]] son, en esencia, "datos de formulario" {#sec-8c911eee119a} Como vimos en el artículo anterior, HTMX recopila los valores de los elementos HTML y los envía al servidor. Esto se hace enviando los valores de entrada dentro de un `
`, incluyendo elementos específicos con `hx-include`, o añadiendo valores adicionales con `hx-vals`. Es decir, la filosofía básica de HTMX se acerca a lo siguiente: * No ensambla objetos JavaScript directamente. * Recopila valores de elementos HTML. * Envía una solicitud al servidor. * Se integra mejor con respuestas de fragmentos HTML que con JSON. Este flujo es sorprendentemente importante. Porque esta estructura **coincide casi exactamente con el flujo típico de procesamiento de formularios en Django**. Django Form también está diseñado con las siguientes premisas: * El usuario introduce datos en un formulario HTML. * El servidor recibe `request.POST`. * El Form valida los datos. * Si hay errores, se vuelve a renderizar. * Si no hay problemas, se guarda y se responde con el resultado. A estas alturas, HTMX y Django Form parecen encajar perfectamente, como Cenicienta y su zapato de cristal. Por lo tanto, podríamos llegar a la siguiente conclusión: **La herramienta de validación de Django que mejor se ajusta a HTMX es Django Form, más que DRF Serializer.** --- ## ¿Por qué Django Form encaja mejor? {#sec-b1e7f36e5f83} DRF Serializer es, sin duda, una excelente herramienta. Sin embargo, si consideramos su contexto de diseño original, un Serializer es una herramienta más orientada a la **serialización de datos y la validación de entradas de API**. En cambio, Django Form fue creado desde el principio para: * Procesar entradas de formularios HTML. * Validación del lado del servidor. * Mostrar mensajes de error. * Mantener los valores de entrada. * Re-renderizar plantillas. Es decir, cuando se combina con un enfoque como el de HTMX, que **"recibe y reemplaza partes del HTML"**, el flujo es mucho más natural. Pensemos en un ejemplo: Un usuario envía un formulario de comentarios. * ¿Qué ocurre si la validación falla? * Los datos introducidos deben mantenerse. * Debe mostrarse qué campos tienen problemas. * El formulario con los errores debe re-renderizarse parcialmente. Django Form maneja muy bien este tipo de experiencia de usuario. Por supuesto, un Serializer también proporciona `errors` y permite la validación. Pero el siguiente paso, **"reconstruir toda la UX del formulario HTML"**, es mucho más fluido con un Form. Por lo tanto, en cuanto a la compatibilidad con HTMX, considerar un Form como la opción predeterminada es lo más apropiado. --- ## La combinación más natural: [[HTMX]] + Django Form {#sec-23fc963f6963} Primero, veamos un ejemplo básico. Un sencillo formulario de registro de tareas pendientes. ### Definición del Form {#sec-fba81a38a40a} ```python from django import forms class TodoForm(forms.Form): title = forms.CharField(max_length=100, label="Título") priority = forms.IntegerField(min_value=1, max_value=5, label="Prioridad") ``` Ahora, en la vista, podemos validar `request.POST` directamente con el Form. ### Procesamiento de la Vista {#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"] # Lógica de guardado # 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, }) ``` El punto clave aquí es muy claro: 1. **Recibir los valores enviados por HTMX como `request.POST`**. 2. **El Form realiza la validación**. 3. **Si tiene éxito, se devuelve un fragmento HTML**. 4. **Si falla, se re-renderiza el Form con los errores**. Este flujo es propio de Django, propio de HTMX y, sobre todo, fácil de mantener. --- ## Volver a mostrar los errores de forma natural en la plantilla {#sec-18af3291951b} Donde Django Form brilla especialmente es aquí. Cuando la validación falla, el objeto Form ya contiene la siguiente información: * Valores introducidos por el usuario. * Mensajes de error por campo. * Errores no relacionados con campos. * El estado de qué campos no son válidos. Por lo tanto, la plantilla parcial puede renderizarlo directamente. ### `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 %}
``` Este ejemplo es muy simple, pero ilustra bien la compatibilidad entre [[HTMX]] y Django Form. * En caso de fallo, el formulario completo puede volver a renderizarse. * Los valores introducidos por el usuario se mantienen. * Los mensajes de error se adjuntan naturalmente junto a cada campo. Si se hubiera utilizado el enfoque tradicional de `fetch()` + JSON + manipulación manual del DOM, se habría necesitado mucho JavaScript para implementar este flujo. Sin embargo, con la combinación de HTMX y Django Form, se puede manejar de forma mucho más sencilla solo con código del lado del servidor y plantillas. --- ## ¿Entonces no necesitamos Serializers? {#sec-5f0d93fcd48a} Decir que **no se necesita un Serializer** sería exagerar. Quizás sería mejor expresarlo así: **No es necesario elegir un Serializer como opción predeterminada.** De hecho, un [[DRF]] Serializer sigue siendo muy atractivo en las siguientes situaciones: * Si ya se está utilizando DRF activamente en todo el proyecto. * Si se desea reutilizar la misma lógica de validación tanto en la API como en las pantallas renderizadas por el servidor. * Si la lógica de validación de entrada es compleja y ya está bien organizada en un Serializer. * Si se planea exponer la misma funcionalidad a aplicaciones móviles o APIs externas en el futuro. Es decir, la cuestión con un Serializer no es **"¿Se puede usar con HTMX?"**, sino más bien **"¿Traer un Serializer aquí aporta algún beneficio a la arquitectura general?"**. --- ## También se puede usar un Serializer {#sec-bfbe9c61b12c} Por ejemplo, supongamos que ya tenemos un Serializer como el siguiente: ```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) ``` En este caso, se puede usar perfectamente en una solicitud 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) ``` Como puede verse, **técnicamente no hay ningún problema**. Un Serializer no es una herramienta que solo acepte JSON. Sin embargo, aquí se revela una sutil diferencia. Al usar un Form: * El mantenimiento de los valores de entrada. * La renderización por campo. * La vinculación de errores. * La conexión con la plantilla. Todo esto se enlaza de forma natural. En cambio, al usar un Serializer: * Se deben desglosar manualmente los `serializer.errors` para que se ajusten a la estructura de la plantilla. * Los valores de entrada existentes deben pasarse por separado. * El desarrollador debe prestar más atención a la conexión con la re-renderización del formulario HTML. Es decir, **se puede usar, pero requiere un poco más de trabajo manual**. Es precisamente por este punto que un Serializer puede sentirse un poco forzado cuando se usa con [[HTMX]]. --- ## Conclusión {#sec-37e5d418cdb7} En el artículo anterior, examinamos cómo [[HTMX]] envía datos. En esta entrega, hemos organizado cómo validarlos de la manera más natural en Django. * HTMX se integra bien con los datos de formulario de forma predeterminada. * Django Form es una herramienta diseñada precisamente para ese flujo. * Por lo tanto, en cuanto a la compatibilidad con HTMX, un Form es la opción más natural. * DRF Serializer se puede usar, pero es una opción más estratégica. Personalmente, creo que para aprovechar HTMX al máximo, es necesario recuperar no solo la **"sensación de manejar AJAX de forma HTML"**, sino también la **"sensación de utilizar Django Form y sus etiquetas de formulario"**. --- **Artículos relacionados** * [Simplificando el desarrollo web dinámico con Django y HTMX (Parte 1)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification/) * [Simplificando el desarrollo web dinámico con Django y HTMX - Ajax (Parte 2)](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-2/) * [Simplificando el desarrollo web dinámico con Django y HTMX (Parte 3): Métodos de integración con Django](/ko/whitedec/2025/1/27/django-htmx-dynamic-web-simplification-3/) * [Simplificando el desarrollo web dinámico con Django y HTMX (Parte 4): ¿Cómo es el payload?](/ko/whitedec/2025/1/27/django-htmx-advanced-features/)