Construir un botón funcional de "agregar al pedido" en Django requiere combinar URLs, vistas basadas en clases y formularios conectados al modelo. Aquí aprendes a usar CreateView, ModelForm y el método form_valid para que un usuario añada productos a una orden activa, una habilidad clave para cualquier desarrollador backend que trabaje con e-commerce o flujos transaccionales.
¿Cómo configurar la URL y la vista CreateView en Django?
El primer paso es declarar la ruta y enlazarla con una vista basada en clase. En el archivo de URLs se agrega un nuevo path llamado agregar_producto y se conecta con una vista que hereda de CreateView, la clase genérica de Django pensada para crear instancias de un modelo.
Dentro de views.py defines una clase CreateOrderProductView que hereda de CreateView e indicas tres atributos básicos:
- El template_name, que apunta al HTML
create_order_product.
- El form_class, que conecta con el formulario que vas a crear.
- El success_url, que redirige al detalle de la orden tras guardar.
Para el success_url se usa reverse_lazy, una utilidad que resuelve la URL por su nombre sin ejecutarse hasta que es necesaria. Esto evita errores cuando las URLs aún no están cargadas en memoria.
¿Qué es reverse_lazy en Django? Es una función que obtiene una URL a partir de su nombre, pero la evalúa solo cuando se necesita. Se usa en atributos de clase para evitar importaciones circulares.
¿Cómo usar ModelForm para conectar el formulario con el modelo?
En lugar de declarar manualmente cada campo, Django ofrece ModelForm, una clase que toma el modelo como referencia y genera los widgets HTML automáticamente según el tipo de dato.
En el nuevo archivo forms.py creas una clase que hereda de ModelForm y dentro defines una clase interna Meta con dos atributos:
model = OrderProduct, que importa el modelo desde .models.
fields = ['producto'], que limita el formulario a un solo campo.
La razón de mostrar solo el producto es que el resto de datos, como la cantidad y la orden, se asignan en el backend. El campo del producto se renderizará como un input oculto en el HTML, ya que el ID se enviará desde el botón "Agregar al pedido".
¿Cuándo conviene usar ModelForm en vez de Form?
Usa ModelForm cuando el formulario refleja directamente un modelo y quieres evitar duplicar definiciones de campos. Usa Form cuando necesitas validaciones o estructuras que no corresponden a un modelo concreto.
¿Cómo sobrescribir form_valid para asignar datos automáticos?
El método form_valid se ejecuta cuando un formulario pasa todas sus validaciones. Sobrescribirlo permite añadir lógica antes de guardar, lo cual es útil cuando faltan campos que no deben venir del usuario.
Dentro de la vista, sobrescribes form_valid(self, form) y haces tres cosas:
- Obtienes o creas la orden activa del usuario con
Order.objects.get_or_create(is_active=True, user=self.request.user).
- Asignas la orden y la cantidad a
form.instance antes de guardar.
- Llamas a
form.save() y retornas super().form_valid(form) para mantener el comportamiento original.
El método get_or_create es clave aquí: intenta recuperar un objeto que cumpla con los filtros y, si no existe, lo crea. Devuelve una tupla con dos valores, el objeto y un booleano que indica si fue creado. Como ese booleano no se usa, se asigna a un guion bajo (_) por convención de Python.
¿Qué hace get_or_create en Django ORM? Busca un objeto con los parámetros dados y lo retorna. Si no existe, lo crea automáticamente. Devuelve una tupla (objeto, booleano_creado).
¿Por qué proteger la vista con un mixin de autenticación?
Si accedes a self.request.user y el usuario no está autenticado, Django devuelve un usuario anónimo, lo que rompe la consulta. Aplicar el mismo mixin de autenticación de la clase anterior redirige automáticamente al login cuando no hay sesión activa.
¿Cómo conectar el botón del template con la nueva vista?
En el template list.html de productos, el botón "Agregar al pedido" se convierte en un formulario con tres elementos esenciales:
method="post", porque modifica datos en el servidor.
action apuntando a la URL nombrada add_product.
- El
csrf_token, obligatorio en cualquier POST en Django.
El ID del producto se envía mediante un input oculto cuyo name es product (igual al campo del formulario) y cuyo value se obtiene del bucle for con {{ product.id }}.
¿Qué errores comunes aparecen al implementar CreateView?
Durante la prueba aparecieron tres errores típicos del desarrollo en Django que conviene reconocer rápido:
- Pasar
self como argumento extra en super().form_valid() cuando solo se requiere form.
- Olvidar el
return en un método de vista, lo que provoca el error view did not return an HttpResponse.
- Dejar comas sobrantes en el HTML al copiar y pegar marcado.
Estos fallos son descriptivos y el traceback de Django suele indicar la línea exacta. Tras corregirlos, el flujo guardó tres veces el mismo capuchino (uno por cada intento), así que se limpió desde el admin eliminando los duplicados de la orden activa.
Con el flujo funcionando ya podrías hacer deploy a producción y permitir que los usuarios administren productos desde una interfaz propia. ¿Qué features añadirías tú? Comparte tus ideas en la sección de comentarios.