Alver Joan perez
Luis Martinez
ProfesorMichael Aguillón
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:
create_order_product.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:
Order.objects.get_or_create(is_active=True, user=self.request.user).form.instance antes de guardar.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.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:
self como argumento extra en super().form_valid() cuando solo se requiere form.return en un método de vista, lo que provoca el error view did not return an HttpResponse.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.
Alver Joan perez
Luis Martinez
ProfesorMichael Aguillón
Bryan Castano
Jhonalbert Aponte
Frandy De La Cruz
Rigoberto Maldonado
Juan Camilo Grisales Arias
Luis Martinez
ProfesorJuan Pablo Lozano
Luis Martinez
ProfesorFranco Silvano Oviedo Arias
Luis Martinez
ProfesorAlonso Montoya
José Luis Ruiz González
David Martín Vergués
Jonnatan Pereira Betancur
Juan Camilo Jaramillo Tascón
Enrique Alejandro Terrazas Huamaní
jesus manuel vergara arias
Juan Alejandro León Lozano
Luis Martinez
Profesorlucas cartisano
Luis Martinez
ProfesorBryan Alexander Ureña Perdomo
Alfredo Olmedo
Santiago J. Vasconcello Acuña
jorge alberto villota leon
David Martín Vergués
David Martín Vergués
Ronaldo Jiménez
Juan Andres Bravo Freitez
Juan Andres Bravo Freitez
Juan Andres Bravo Freitez
El curso va muy bien, el profesor sabe mucho del tema, valio la espera, espero que hayan mas clases y mas contenido con el mismo instructor
Muchas gracias por el comentario! Estaré pendiente si surge alguna duda o un problema que necesites ayuda para solucionar!
I agree, el profesor sabe y explica de manera clara y conciza, espero más clases para profundizar este framework que es tan tan potente
Hola Chicos, Yo he logrado funcionarlo alfin despeus de 50 minutos.
/products/
/add_product/
//my_orders/
/order_details/
\nEste es el codigo actualxiado de la clase OrderCreateView() en ./orders/views.py :
class OrderCreateView(LoginRequiredMixin, CreateView): model = Order form_class = OrderForm template_name = 'orders/order_form.html' success_url = reverse_lazy('order_list') def form_valid(self, form): # Attach the current user before saving the order instance form.instance.user = self.request.user return super().form_valid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['order_form'] = self.get_form() return context
Esta es la tabla Orders en base datos:
SELECT * FROM orders_order ORDER BY created_at DESC LIMIT 3;
8|ORD-20260111234556-7FFE473A|Bryan David|beau.ghjg.boy007@gmail.com|1|2026-01-11 23:45:56.789218|2026-01-11 23:45:56.789249|2
7|ORD-20260111234508-60B0E2B1|Bryan David|beau.ghjg.boy007@gmail.com|1|2026-01-11 23:45:08.678446|2026-01-11 23:45:08.678471|2
6|ORD-20260111234436-0EC46344|Bryan David|beau.ghjg.boy007@gmail.com|1|2026-01-11 23:44:36.712550|2026-01-11 23:44:36.712572|2
sqlite>
Consulta
Veo que tenemos dos path llamados add_product:
De products
path('agregar/', ProductFormView.as_view(),name = "add_product"),
y de orders
path("agregar-producto",CreateOrderProductView.as_view(), name = "add_product")
Eso no generaría conflictos?? Gracias
Creo que si, por lo que antes de que me de el error yo cambie el name para que sean diferentes hahaha
Buen dia campeon...
Un par de horas investigando, quedo de esta manera.
Saludos.
Que buen curso.
Muchas gracias por tu comentario! Por aca pendiente ante cualquier duda
El mio va quedando asi:
Muy contento con este curso 😊
Que bueno que te guste! por acá estoy disponible si algun duda.
Como en todas las clases, segui todos los pasos, pero a lo ultimo al momento de dar clic en el boton "agregar pedido" no me arroja error ni nada, pareciera que estuviera redireccionando a la misma pagina, y cuando hago refresh me muestra la pagina en blanco y en la url aparece la direccion /pedidos/agregar-producto. No se que pudo haber faltado, reviso el codigo y esta igual como el tutor lo implemento; lo unico que me parece curioso es que el tutor dejo el create_order_product.html vacio; no se si esto influye en algo
Sí eso influye, si quieres me puedes mostrar los logs que hay en la consola para ayudarte mejor!
a alguien al momento de hacerle click al botón de agregar, le genera un error: integridad Error at /pedidos/agregar-producto
exception value: NOT NULL
A mí me salía el mismo error con el id porque tenía escrito form_invalid en lugar de form_valid en la clase CreateOrderProductView
También checa si te falta correr migraciones
yo tengo dudas en la vista "CreateOrderLineView" tenemos un campo template_name = "orders/create_order_product.html" y ese html esta vacío en mi caso cuando le doy a añadir producto me lleva a esa pagina en blanco
Me pasaba lo mismo! En mi caso el problema fue que el "name" del <input> en mi template era diferente al campo dentro de "fields" en forms.py
Profe te olvidaste de mostrartnos como se construia el HTML de mi-orden
El html está en el repositorio de Github que se compartión hace algunas clases, este es el html:
{% extends "base.html" %} {% block content %} <div class="max-w-4xl mx-auto p-6 bg-white rounded-lg shadow-md"> <h2 class="text-2xl font-bold mb-4">Detalles de la Orden</h3> <div class="mb-2"> <span class="text-lg font-semibold">Usuario: </span> <span class="text-lg">{{ order.user.username|title }}</span> </div> <div class="mb-2"> <span class="text-lg font-semibold">Fecha de la Orden: </span> <span class="text-lg">{{ order.order_date|date:"F j, Y H:m" }}</span> </div> <div class="mt-6"> <h3 class="text-xl font-bold mb-2">Artículos en tu orden:</h4> {% for product_order in order.orderproduct_set.all %} <div class="flex justify-between items-center py-2 border-b"> <div class="text-lg">{{ product_order.product.name }}</div> <div class="text-lg font-semibold">{{ product_order.product.price }}</div> </div> {% empty %} <div class="text-red-500">No hay artículos en tu orden</div> {% endfor %} </div> </div> {% endblock content %}
Todo va genial:
debo siempre tener templates o puedo ir consumiendo las API desde un front desarrollado con React? o sería mejor dejar de usar React y hacer todo solo desde Django?
SI usas django solo sí es mejor usar solo templates, pero si usas django rest framework puedes usar react.
El reescribir la funcion form_valid(), no viola los principios solid? No es una mala práctica?
Al reusar las clases que viene por defecto en Django y sobre escribir sus methods no estamos violando las buenas prácticas, al contrario son buenas prácticas reusar y cambiar funcionalidades de esta manera
Cuando sobreescribes el funcionamiento de un método de una clase A, cuando este método fue heredado de una clase B. Esto se cataloga como <u>polimorfismo</u>, es un pilar de la programación orientada a objetos.
Porque usar un _ en vez de una Variable sin uso:
Cuando tienes una variable sin uso en tu código, es decir, una variable que se declara pero nunca se utiliza para almacenar o manipular datos, pueden surgir algunos problemas:
Ahora bien, ¿por qué usar el guion bajo (_)? En muchos lenguajes de programación, el guion bajo se utiliza como un “nombre de descarte” o “nombre de variable ignorada”. Al asignar un valor a _, estás indicando que no te importa el valor y que no planeas utilizarlo. Esto es especialmente útil en situaciones como bucles donde necesitas iterar sobre una secuencia, pero no necesitas el valor de cada elemento individualmente. Al usar _, estás comunicando de manera explícita que la variable no tiene un propósito específico y evitas advertencias o errores del compilador relacionados con variables no utilizadas.
En resumen, es una buena práctica eliminar las variables sin uso de tu código y, cuando sea necesario, utilizar _ para indicar que una variable no tiene un propósito relevante en ese contexto.
El LoginRequiredMixin en Django se utiliza para restringir el acceso a ciertas vistas para usuarios no autenticados. Al heredar este mixin en tus vistas, aseguras que solo los usuarios logueados puedan acceder a la funcionalidad que has definido, redirigiéndolos a la página de inicio de sesión si intentan acceder sin estar autenticados. Esto es útil para proteger áreas de tu sitio que requieren un usuario registrado, mejorando la seguridad y la experiencia del usuario.
Buenas Tardes
Estoy teniendo problemas con la siguiente linea de código
order, _ = Order.objects.get_or_create( is_active=True, user=self.request.user, )
Al ejecutarse desde el servidor e intentar crear un nuevo producto aparece el siguiente error:
MultipleObjectsReturned at /pedidos/agregar-producto
Hice la comparativa del fuente de y lo tengo igual, alguien me podría ayudar.
te da ese error xq ese usuario tiene más de un order con is_active=True, puedes ir por el admin de django y editarlo o borrar los orders asociados a ese user y quedarte solo con uno
Bueno curso y buen profesor, espero que sigan ampliando la formación en Django y se toquen temas más complejos. Saludos!
Muy buen curso, tenga que parar y respirar jajajaja para procesar tanta info. Gracias al profe
a mi se saltaba a otra vista al momento de hacer un pedido (create_order_product) y esta fue mi solución, el DeailView esta diseñada para que muestre o objeto en especifico como un pk o un slug, por eso, rediseñe la vista(MyOrder):
class MyOrder(LoginRequiredMixin, TemplateView): template_name = 'order/order.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) order = Order.objects.filter(is_active=True, user=self.request.user).first() context['order'] = order if order: total = sum(order_product.product.price * order_product.quantity for order_product in order.orderproduct_set.all()) else: total = 0 context['total'] = total return context ```class MyOrder(LoginRequiredMixin, TemplateView): template\_name = 'order/order.html' def get\_context\_data(self, \*\*kwargs): context = super().get\_context\_data(\*\*kwargs) order = Order.objects.filter(is\_active=True, user=self.request.user).first() context\['order'] = order if order: total = sum(order\_product.product.price \* order\_product.quantity for order\_product in order.orderproduct\_set.all()) else: total = 0   context\['total'] = total return context
class MyOrder(LoginRequiredMixin, TemplateView): template_name = 'order/order.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) order = Order.objects.filter(is_active=True, user=self.request.user).first() context['order'] = order if order: total = sum(order_product.product.price * order_product.quantity for order_product in order.orderproduct_set.all()) else: total = 0 context['total'] = total return context
código arreglado abajo jeje