TransWikia.com

Problema con errores en forms Django

Stack Overflow en español Asked by Lucas Leone on August 27, 2021

Estoy teniendo un problema con mi forms. Hice una funcion que verifique si las contraseñas son iguales, si esto no es asi devuelve un raise con un mensaje. El problema que ese mensaje no me sale. Tengo otras 2 funciones muy parecidas con el username y el email y si funcionan.

Cambios: Adjunte todo el codigo del forms y tambien el del html.
Probe cambiando la funcion de clean sacando el data, y obteniendo los datos a traves del self.cleaned_data, pero sigue igual. En la otra aplicacion que habia hecho en modo de practica no hubo ningun problema.

Dejo el codigo:

forms.py

class SignupForm(forms.Form):
username = forms.CharField(
    min_length=4,
    max_length=50,
    label='Nombre de usuario'
)
password = forms.CharField(
    min_length=4,
    max_length=50,
    widget=forms.PasswordInput(),
    label="Contraseña"
)
password_confirmation = forms.CharField(
    min_length=4,
    max_length=50,
    widget=forms.PasswordInput(),
    label='Confirmar contraseña'
)

first_name = forms.CharField(
    min_length=2,
    max_length=50,
    label='Nombre'
)
last_name = forms.CharField(
    min_length=2,
    max_length=50,
    label='Apellido'
)
email = forms.CharField(
    widget=forms.EmailInput(),
    label='Email'
)
def clean_username(self):
    username = self.cleaned_data['username']
    username_taken = User.objects.filter(username=username).exists()
    if username_taken:
        raise forms.ValidationError('El nombre de usuario ya esta en uso.')
    return username
def clean_email(self):
    email = self.cleaned_data['email']
    email_taken = User.objects.filter(email=email).exists()
    if email_taken:
        raise forms.ValidationError('El email ya esta en uso.')
    return email
def clean(self):
    data = super().clean()
    password = data['password']
    password_confirmation = data['password_confirmation']
    if password != password_confirmation:
        raise forms.ValidationError('Las contraseñas no coinciden.')
    return data
def save(self):
    data = self.cleaned_data
    data.pop('password_confirmation')
    user = User.objects.create_user(**data)
    profile = Profile(user=user)
    profile.save()

signup.html

<form action="{% url 'users:signup' %}" method="POST">
            {% csrf_token %}
            {% for field in form %}
                <p>
                    {{ field.label_tag }}<br>
                    {{ field }}
                {% for error in field.errors %}
                    {{ error }}
                {% endfor %}
                </p>
            {% endfor %}
            <br>
            <button class="register-button" type="submit">Registrarse</button>
        </form>

One Answer

El problema es que el error que levantas no es de un campo en especifico y esto es porque lo levantas en el método clean, y tu solo muestras los errores de los campos:

{% for error in field.errors %}
    {{ error }}
{% endfor %}

Entonces hay varias soluciones, una es indicando el campo al momento de levantar la excepción ValidationError:

raise forms.ValidationError({
    'password_confirmation': forms.ValidationError('Las contraseñas no coinciden.')
})

O puedes hacerlo así (personalmente, yo uso esta forma, es mejor, ademas que solo tienes que llamar el método y ya):

self.add_error('password_confirmation', forms.ValidationError('Las contraseñas no coinciden.'))

O así:

self.add_error('password_confirmation', 'Las contraseñas no coinciden.')

Django recomienda la primera forma, pero en la documentación, usa la segunda forma, y pues....

El caso es si usas la segunda forma, Django se encarga de convertir el mensaje de error (str) a una instancia de ValidationError, esto se puede ver en el código fuente (method add_error):

def add_error(self, field, error):
    """
    ...
    """
    if not isinstance(error, ValidationError):
        # Normalize to ValidationError and let its constructor
        # do the hard work of making sense of the input.
        error = ValidationError(error)

Entonces no se cual de las dos es mejor XD....

Por otra parte cabe recalcar que si utilizamos el método add_error, se elimina automáticamente el campo del cleaned_data.


Si no quieres hacer lo anterior, entonces tu <form> puede ser así:

<form action="" method="POST">
    {% csrf_token %}

    {{ form.errors }} <---

    {% for field in form %}
        <p>
            {{ field.label_tag }}<br>
            {{ field }}
        {% for error in field.errors %}
            {{ error }}
        {% endfor %}
        </p>
    {% endfor %}
    <br>
    <button class="register-button" type="submit">Registrarse</button>
</form>

El "problema" es que el error se mostrara al principio del form (o puedes ponerlo abajo).

Espero haberte ayudado.

Correct answer by Julio Cesar on August 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP