La funcionalidad de formularios en Django permite a los desarrolladores crear, validar y gestionar formularios de manera eficiente y organizada. A continuación, exploraremos cómo crear formularios en Django paso a paso.
¿Cómo se crean formularios en Django?
Para crear un nuevo formulario en Django, primero se debe crear una clase que herede de forms.Form. Esta clase contendrá todos los campos que queremos incluir en el formulario.
Crear el archivo forms.py:
from django import forms
classProductForm(forms.Form): name = forms.CharField(max_length=200, label='Nombre') description = forms.CharField(max_length=300, label='Descripción') price = forms.DecimalField(max_digits=10, decimal_places=2, label='Precio') available = forms.BooleanField(initial=True, label='Disponible', required=False) photo = forms.ImageField(label='Foto', required=False)
¿Cómo se manejan los datos del formulario en Django?
Una vez que el formulario está creado, necesitamos definir cómo manejar los datos cuando el usuario envía el formulario. Esto incluye validar los datos y guardarlos en la base de datos.
El CSRF token es una medida de seguridad que protege contra ataques de tipo Cross-Site Request Forgery. Django lo incluye automáticamente en los formularios para asegurar que las solicitudes provengan de fuentes confiables.
¿Cómo se maneja la redirección después de enviar el formulario?
La redirección después del envío del formulario se maneja configurando el parámetro success_url en la vista, utilizando reverse_lazy para obtener la URL de destino.
¿Cómo se valida y guarda el producto?
Cuando el formulario es válido, el método form_valid se encarga de llamar al método save del formulario para guardar el producto en la base de datos.
Si ud llego hasta aqui y se confundio con el enrutamiento le voy a dejar una forma mas facil de entenderlo rapido y sin tanto dolor:
la ruta del url general siempre va a ir primero ejemplo: esto porque asi se puso en el include
luego viene la ruta de la aplicacion o sea lo que puso en el url de su app ejemplo: si ud puso add_product/ entonces la ruta quedaria `` como vemos /products/ es como ud le llamo cuando uso el include y add_products es el nombre que le dio a la clase que renderiza su template
Una forma que encuentro más "directa" de ver si efectivamente se creó el producto es utilizar la shell de la base de datos, que en este caso es sqlite.
Sabemos que la base de datos se llama db.sqlite3, así que ubicados en la carpeta de coffee_shop dentro de la terminal podemos ingresar: sqlite3 db.sqlite3
Esto nos ingresará a la shell de sqlite y allí podremos entonces listar las tablas que están en la base de datos con el comando .tables
Y finalmente podemos hacer un SELECT * FROM products_product; y de esta forma vemos que efectivamente se agregó el ítem.
Si queremos ver el nombre de las columnas no se nos puede olvidar ingresar el comando .head on
Para salir y regresar a la terminal simplemente le das .exit.
A mí se me hace más intuitiva y directa esta forma, que utilizar el ORM de Django y manipular los objetos en Python.
gracias, me hacia falta el .head on!
Reflexión
Siento que el profesor no esta aplicando ningun principio o patrón de diseño, entiendo que es una clase básica pero estaria padre ir ordenando nuestro código.
Mi reflexión esta bien hacerlo así para seguir el curso pero si esta algo confuso trabajar sin un orden, yo esperaba que los formularios generará algun nuevo repositorio o alguna explicación de porque hacerlo así
Ojo comento esto como posible mejora o aporte, tal vez al final del curso me diga -> ¡ Haaaa por eso lo hicimos así !
El curso va bien pero hay detalles que me digo esto lo pudiero realizar de esta manera.
Gracias si llegaste hasta aquí. Solo deseo que todos podamos avanzar a nuestro ritmo sin perder los detalles que es lo mas importante en este mundo de dsarrollo .
Si, yo al menos tengo una base y voy organizando mi codigo pero te entiendo en lo personal voy poco a poco.. prefiero primero hacer este proyecto como un rough y luego ir refinando gradualmente como dice el dicho.. haz primero que exista.
¿A quién no se le guarda la foto en la base de datos desde este form view y sí se guarda desde el admin?
Creo que ese es el reto, venia a ver si alguien lo logro en los comments hahaha, sino, tocara hacerlo.
para lograrlo, hay que colocar en el HTML, en el form esto: enctype="multipart/form-data" para que acepte la imagen
Para aquellos que aun no han hecho el reto.
Es importante que revisen:
La seccion de Views dentro de su app
La generacion del Template para que se ligue su View con su template.
No olviden tampoco agregar la URL de la lista a la seccion de URLS
Despues no olviden cambiar el Success url a su nuevo template de lista para que se redirija
El CSRF token es crucial para la seguridad, ya que evita ataques de Cross-Site Request Forgery (CSRF). Si se olvida, Django devolverá un error 403, impidiendo que usuarios externos envíen datos maliciosos a través de formularios desde otros sitios web.
CSRF (Cross-Site Request Forgery) es un tipo de ataque web donde un atacante induce a un usuario autenticado a ejecutar acciones no deseadas en una aplicación web en la que está logueado, sin que el usuario lo sepa.
Las generic views en Django se utilizan para simplificar el manejo de tareas comunes en la web, como mostrar listas de objetos, crear, actualizar o eliminar registros. Permiten reutilizar código y reducir la cantidad de lógica que debes implementar manualmente para estas operaciones básicas.
Usa ModelForm cuando trabajes directamente con modelos y no necesites una lógica especial.
Usa forms.Form cuando necesites mayor control o la creación no esté vinculada directamente a un modelo.
Creo que en este caso correspondería usar forms.ModelForm e importar el modelo de .models? o No?
Otra forma: instalar la extensión SQLite Viewer en Code y dar click sobre la base de datos db.sqlite3, buscar la tabla products_products y revisarla.
Funciona bien gracias a chatgpt, ya que había que hacer más configuraciones de las esperadas para ver imágenes:
Aporte para agregar widgets al forms y darle una personalizacion como lo es con el atriubuto 'size':'50' para aumentar el tamano del input, agregar placeholder y seleccionar seleccionar el campo NumericInput para el precio asi no admite escritura en ese campo.
Yo en este punto tengo un error en mi función save de mi forms.py pero no he entendido por que ?? linea 12 Product.objects.create marca “Class ‘Product’ has no ‘objects’ member”, pude ir mas adelante en el curso pero marca error 500 al tratar de guardar el formulario y aunque ejecuta no guarda datos, como se podría resolver o que falta ??
Hola Ernesto espero te encuentres muy bien, analizando un poco el error que lanza es debido al linter de python, no en en Django como tal. El problema a revisar sería la razon por la cual no te deja guardar la data, sería necesario revisar los settings de la BD, como está diseñado el modelo, si ya se han hecho las migraciones con makemigrations y migrate, entre otras cosas. Aunque el comentario tuyo sea de varios meses espero que hayas logrado dar con la solución
Saludos!
Reto: crear una success URL que contenga un listado de todos los productos añadidos.
Para empezar, lo que hice fue crear una ruta adicional en el archivo <u>products/urls.py</u>, esta la llamé "success/"
path('success/', success, name="success")
Luego, creamos la vista en <u>products/views.py</u>, la llamaremos tambien success, importaremos el modelo Products y lo pasaremos como contexto al template success.html. Teniendo en cuenta que Products es una clase podremos acceder a todos los atributos (datos) de esta con el método all(): def success(request): all_products = Products.objects.all()return render(request, 'success.html', {'products': all_products})
Adicionalmente en la clase ProductFormView, actualizaremos el parametro de reverse_lazy('nombre_url') por reverse_lazy('success_o_como_hayas_llamado_la_url')
Por último, creamos el archivo success.html, recorremos con un for el contexto ('products' en mi caso), y imprimimos el nombre junto con el precio:
<ol> {% for i in products %} <li>{{i.name}} {{i.price}}</li> {% endfor %}</ol>
Y ya tendremos un resultado similar a este:
Espero te haya servido : D
Saludos!
Agregue esta parte para hacer una validación en la base de datos si ya existia el producto, en forms.py antes de save
def clean_name(self): name = self.cleaned_data.get("name")ifProduct.objects.filter(name__iexact=name).exists(): raise forms.ValidationError("Este producto ya existe")return name
Ademas tambien hice el campo name como unique en models
name = models.CharField(max_length=200, verbose_name="nombre", unique=True)
en form del template add_pro...
agregar esto: method="post" enctype="multipart/form-data"
lo que hace es empaqueta los campos (text, files, etc) cuando se hace un post> es util para agregar las imagenes.
Buenas noches colegas? Cual es la importancia de darle label en el form si al definir el verbose_name en los modelos ya los tomas a pesar de escribirlo los labels en el form?
Hola, pues hice un cambio en la definición de los form y pude notar que se modifica la label, espero que esto sea de ayuda.
Hola Juan, si me di cuenta también que los label en el forms.py se refleja en el formulario. Y los verbose_name en los modelos se reflejan en el admin.
¿Todo bien hasta que le agregó esta función y dejo de correr, si la comento corre pero no se guarda los datos:
Tengo una consulta: ¿me podría explicar, por favor, con qué combinación de teclas copió y pegó todos los campos en la función?
Te refieres a cómo seleccionar mas de un cursor a la ves en VS Code? CTRL+ALT y flecha de abaj/arriba o clickeando con el mouse. Después manteniendo apretados CTRL y flecha izquierda/derecha puedes saltar palabras o seleccionar otras, etc.