Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Validación de formularios

27/37
Recursos

Para aprender a validar los campos de un formulario vamos a actualizar el registro de usuarios.
Hasta este momento el script de validación del formulario Signup está escrito directamente en la vista, y a pesar de que no genera ningún error, puede convertirse en un problema, así que lo recomendable es separarlo. Crearemos un nuevo form con la clase forms.Form, también vamos a introducir un nuevo concepto relacionado con formularios: los widgets.

Los widgets en Django, son una representación de elementos de HTML que pueden incluir ciertas validaciones. Por default todos los campos son requeridos. Los datos depurados se pueden consultar con self.cleaned_data['_nombre_del_field_']

Aportes 33

Preguntas 17

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Si alguien quiere ocultarle el label y añadir bootstrap a cada input deben especificar label = False y usar attrs dentro del respectivo widget

username = forms.CharField(label=False,min_length=4,max_length=50, widget = forms.TextInput(attrs={'placeholder':'username','class': 'form-control','required': True}))

De esta manera queda idéntico al formulario anterior

Para que quede exactamente igual que el formulario anterior pueden copiar y pegar el siguiente codigo, si usaron los mismos nombres de variables. Si no, renombrenlas.

username = forms.CharField(label=False,min_length=4,max_length=50, widget = forms.TextInput(attrs={'placeholder':'Nombre de usuario','class': 'form-control','required': True}))

    password = forms.CharField(label=False,max_length=70, widget=forms.PasswordInput(attrs={'placeholder':'Escribe tu contraseña','class': 'form-control','required': True}))

    password_confirmation = forms.CharField(label=False,max_length=70, widget=forms.PasswordInput(attrs={'placeholder':'Confirma tu contraseña','class': 'form-control','required': True}))

    first_name = forms.CharField(label=False,min_length=2,max_length=50,widget = forms.TextInput(attrs={'placeholder':'Nombres','class': 'form-control','required': True}))

    last_name = forms.CharField(label=False,min_length=2,max_length=50,widget = forms.TextInput(attrs={'placeholder':'Apellidos','class': 'form-control','required': True}))

    email = forms.EmailField(label=False,min_length=6,max_length=70,widget=forms.EmailInput(attrs={'placeholder':'Correo electrónico','class': 'form-control','required': True}))

OJO, buen curso pero se les olvidó hablar de los Model Forms, que si bien pueden ser un poco más complejos (init, validators, update, super(), args, kwargs…) son herramientas poderosas para gestionar data. Más información :
https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#

Para conservar los estilos de bootstrap lo que hice fue modificar la propiedad widget de la siguiente manera (users/forms.py)

class SignupForm(forms.Form):
    """Sign up form."""
    username = forms.CharField(
        min_length=4,
        max_length=50,
        widget=forms.TextInput(
            attrs={
                'placeholder': 'Username',
                'class': 'form-control',
                'required': True
                }
        )
    )
    password = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.PasswordInput(
            attrs={
                'placeholder': 'Password',
                'class': 'form-control',
                'required': True
            }
        )
    )
    password_confirmation = forms.CharField(
        min_length=6,
        max_length=70,
        widget = forms.PasswordInput(
            attrs={
                'placeholder': 'Password Confirmation',
                'class': 'form-control',
                'required': True
            }
        )
    )

    first_name = forms.CharField(
        min_length=3,
        max_length=50,
        widget=forms.TextInput(
            attrs={
                'placeholder':'First name',
                'class': 'form-control',
                'required': True
                }
            )
        )
    last_name = forms.CharField(
        min_length=3,
        max_length=50,
        widget=forms.TextInput(
            attrs={
                'placeholder': 'Last name',
                'class': 'form-control',
                'required': True
                }
        )
    )

    email = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.EmailInput(
            attrs={
                "placeholder": "email",
                "class": "form-control",
                'required': True
            }
        )
    )
	.
	.
	.
	.
}

Y en el template llamaría así a la vista. (template/users/signup.html)

{% extends "users/base.html" %}

{% block head_content %}
    <title>PlatziGram Sign up</title>
{% endblock %}

{%block container %}
    {% if error %}
        <p class="alert alert-danger">{{ error }}</p>
    {% endif %}
    <form action="{% url 'signup' %}" method="POST">
        {% csrf_token %}
        {% for elem in form %}
            <div class="form-group">
                {{ elem }}
            </div>
        {% endfor %}
        <button class="btn btn-primary btn-block mt-5" type="submit">Register!</button>
    </form>
{% endblock %}

Yo tenia entendido que la función _save _ solo podia ser utilizado si se hereda de ModelForms, de hecho, a mi así como explica no me esta funcionando, me sale el siguiente error:

’SignupForm’ object has no attribute 'save’

Python y Django mantienen una fuerte filosofía en DRY (Don’t Repeat Yourself) y lo que hemos visto en este curso con los forms de Django rompe toooooda esa filosofía, creo que bien pueden aplicarse librerías como Django Crispy Form (https://django-crispy-forms.readthedocs.io/), que hace una integración con los Forms, validaciones, y sobre todo Bootstrap de una forma increíblemente simple.

Si en lugar de forms.Form se utilizaran forms.ModelForm sería todavía más sencillo.

No está de más conocer cómo se haría de manera “manual”, pero llegar al final de la sección de forms y no ver el funcionamiento de un ModelForm me deja con una sensación de que algo faltó, la verdad es que esperaba un poco más.

Platzi y sus cursos tipicos donde solo dicen, se hace esto y esto, ah y esto hace esto, esta clase esta mala… no hay fundamentos ,no se entiende

Se me ocurrió esta manera para que una vez que el usuario haya hecho sign up, este haga login y haga redirect al feed

En (users/views)

def signup_view(request):
    """Sign up view."""
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            form.save()
            user = authenticate(
				request, 
				username=form.cleaned_data['username'],								 									 
    				password=form.cleaned_data['password']
	    )
            login(request, user)
            return redirect('feed')
    else:
        form = SignUpForm()

    return render(
        request=request,
        template_name='users/signup.html',
        context={'form': form}
    )

les comparto una libreria que hace mas facil la creacion de forms dinamicos con estilos y atributos custom https://github.com/jazzband/django-widget-tweaks

además mi codigo usando el mismo

{% extends 'users/base.html' %}

{% load widget_tweaks %}

{% block head_content %}
    <title>
      Platzigram Signup
    </title>    
{% endblock head_content %}


{% block container %}

  {% if errors %}
    <p class="alert alert-danger">{{errors}}</p>
  {% endif %}
  <h1 class="text-center">
    Sign up!
  </h1>
  <form action="{% url 'signup' %}" method="POST" >
    {% csrf_token %}

    {% for field in form  %}
      <div class="form-group">
        {% render_field field|add_error_class:"is-invalid" placeholder=field.label class+="form-control" %}
        {% if field.errors %}
          <div class="invalid-feedback">
            {% for error in field.errors %}{{ error }}{% endfor %}
          </div>
        
        {% endif %}
      
      </div>
    {% endfor %}

    
    <button class="btn btn-primary btn-block mt-5" type="submit">
      Register
    </button>


  </form>
{% endblock container%}

perfecto que dimamico el template form {{ form.as_p }} , investigare mas sobre ello con el fin que el diseño sea mas bonito pero asi de funcional de implementar

Alguien sabe Porqué el profesor usa forms.CharField en lugar de forms.EmailField?? en el form?

Asi me siento con este curso “Somos la copia de la copia que el profesor esta haciendo”,

Este curso me esta desanimando… esperaba los secretos de django orientado al backend pero casi todo está enfocada al front 😦

como en 11:44 ,sin ganas de enseñar, sin motivacion, sin preocuparse de que los estudiantes entiendan, solo es una exposicion de lo que es Django

La simplicidad del código es genial…
Mucho más legible que antes

Hola. He tenido dudas respecto a la logica de, por ejemplo, la funcion signup.

Lo que yo entiendo, y agradeceria si de estar mal, alguien me lo pudiera explicar correctamente, es que, al poner en la url /users/signup/ el view que se va a llamar es la funcion signup, esta view lo que hace es verificar si el metodo del request es POST, yt si lo es, almacenar en una variable form los datos de la peticion de tipo POST (que entiendo es generada por el template signup.html al darle submit al formulario) para posteriormente guardarla con el metodo save() que la guarda directamente hacia la base de datos especificada en settings. Como en primera instancia este request no es de tipo POST, porque viene de llamar directamente la URL (No estoy seguro si es de tipo GET(?)), entonces llama en la variable form a la clase (validacion de formularios de Django) SignupForm para que valide los campos del formulario en el template signup.html que es llamado por render en al respuesta de la funcion(?)

Tengo algunas dudas, primeramente, si mi plateamiento es correcto, claro y en segundo lugar, de estar en lo correcto, por indentacion de python, el return de la funcion se ejecuta DESPUES del if que pregunta si la peticion es de tipo request. Verdad? Por que no se llama al template justo al inicio de la vista, para que se llame directamente el formulario y solo se pregunte si la peticion es de tipo POST una vez se haya llenado el formulario y este haya cambiado la peticion a POST.

Yo como lo entiendo es que primero pregunta si es de tipo POST el request, como no lo es, llama el template con el formulario y la validacion del formulario para que cambien el tipo de request a POST y luego vuelve apreguntar si es POST, si lo es, y se ejecuta el resto del if. Parece que no es el camino mas directo.

Muchas gracias si leen esa explicacion tan larga y me pueden aclarar esa pequena duda jeje.

def signup(request):
    """Signup View"""

    if request.method == 'POST':
        form = SignupForm(request.POST)
        if form.is_valid:
            form.save()
            return redirect('login')
    else:
        form = SignupForm()

    return render(
        request = request,
        template_name = 'users/signup.html'
        context = 
        )```

Les dejo el formulario con las clases de bootstrap.

 username = forms.CharField(min_length=4, max_length=50,
    widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Username'})
    )

    password = forms.CharField(
        max_length=70,
        widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'})
    )
    password_confirmation = forms.CharField(
        max_length=70,
        widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'})
    )

    first_name = forms.CharField(min_length=2, max_length=50,
    widget=forms.TextInput(attrs={'class':'form-control','placeholder':'First Name'})
    )
    last_name = forms.CharField(min_length=2, max_length=50,
    widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Last Name'})
    )

    email = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.EmailInput(attrs={'class':'form-control','placeholder':'Email Addres'})
    )

Para mostrar las validaciones del formulario de signup de la misma manera que en el de update_profile hice lo siguiente:

templates/users/signup.html

...

<div class="form-group">
            <input
              class="form-control {% if form.username.errors %}is-invalid{% endif %}"
              type="text"
              placeholder="Username"
              name="username"
              value="{% if form.errors %}{{ form.username.value }}{% endif %}"
            />
            <div class="invalid-feedback">
                {% for error in form.username.errors %}
                    {{ error }}
                {% endfor%}
            </div>
        </div>

...

users/forms.py

...

def clean(self):
        """Verify password confirmation match."""

        data = super().clean()

        password = data['password']
        password_confirmation = data['password_confirmation']

        if password != password_confirmation:
            ex = forms.ValidationError('Passwords do not match.')
            self.add_error('password', ex)
            self.add_error('password_confirmation', ex)
            raise ex

        return data

...

Hasta ahora el curso ha sido exelente

Podemos eliminar el label especificando este como vacío:

username = forms.CharField(label="")

Excelente clase!

Me surgió una pregunta. Cómo se haría cuando en el mismo template hay dos formularios?

why clean_ ?

Aún cuando usamos el ‘form’ diretactamente en el template:

{{ form.as_p }}

Podemos agregar clases con la app de 'widget_tweaks’
Aquí hay un tutorial de como usarlo:
https://platzi.com/tutoriales/1318-django/4060-utilizando-bootstrap-4-con-django-forms-y-widget-tweaks/

Un minimo detalle:Pienso que para el logout tambien deberia agregarse el @login required

Me recomiendan mucho en vez de crear los diccionarios con los corchetes usar el método de python dict() ¿que pensas sobre eso?

En que momento el profe cargo los post en el administrador de django?

Estimada comunidad, encontré una forma de agregarle las clases a los campos desde el propio formulario (users/forms.py):

class SignUpForm(forms.Form):
    usermame = forms.CharField(min_length=5, max_length=50, widget = forms.TextInput(attrs={'class':'form-control'}))
    password = forms.CharField(max_length=140, widget = forms.PasswordInput(attrs={'class':'form-control'}))
    password_confirmation = forms.CharField(max_length=140, widget = forms.PasswordInput(attrs={'class':'form-control'}))
    first_name = forms.CharField(min_length=5, max_length=50, widget = forms.TextInput(attrs={'class':'form-control'}))
    last_name = forms.CharField(min_length=5, max_length=50, widget = forms.TextInput(attrs={'class':'form-control'}))
    email = forms.CharField(min_length=4, max_length=70, widget = forms.EmailInput(attrs={'class':'form-control'}))```

Referencia: http://www.learningaboutelectronics.com/Articles/How-to-add-a-class-or-id-attribute-to-a-Django-form-field.php#:~:text=and%20id%20attributes.-,In%20order%20to%20add%20a%20class%20or%20id%20attribute%20to,%3D%7B'class'%3A'some_class'%7D.

Les dejo mi codigo de como mostrar el error ya que todos los codigos que aparecian abajo no me servian.

{% block container %}
    {% if form.errors %}
        {% for field in form %}
            {% for error in field.errors %}
                <div class="alert alert-danger alert-dismissible fade show" role="alert">
                    {{ error|escape }}
                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
            {% endfor %}
        {% endfor %}
        {% for error in form.non_field_errors %}
            <div class="alert alert-danger alert-dismissible fade show" role="alert">
                {{ error|escape }}
                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
        {% endfor %}
    {% endif %}
    <form method="POST" action="{% url 'signup' %}">
        {% csrf_token %}

        {% for field in form %}
            <div class="form-group">
                {{ field }}
            </div>
        {% endfor %}

        <button class="btn btn-primary btn-block"type="submit">Register</button>
    </form>
    <p class="form-text mt-2">If you already have an account <a href="{% url 'login' %}">Log in!</a></p>
{% endblock %}

Buenas noches!! Cómo se pudiera ingresar multiples datos a una tabla desde un documento Excel??

Sumamente bello el final de la clase. La manera de agrupar vistas, forms, y templates. Me gustó un montón.

Para aprender a validar los campos de un formulario vamos a actualizar el registro de usuarios.
Hasta este momento el script de validación del formulario Signup está escrito directamente en la vista, y a pesar de que no genera ningún error, puede convertirse en un problema, así que lo recomendable es separarlo. Crearemos un nuevo form con la clase forms.Form, también vamos a introducir un nuevo concepto relacionado con formularios: los widgets.

Los widgets en Django, son una representación de elementos de HTML que pueden incluir ciertas validaciones. Por default todos los campos son requeridos. Los datos depurados se pueden consultar con self.cleaned_data[‘nombre_del_field’]

Excelente, pero como todo es de cuidado, muy buen ejercicio