Can not validate the AuthForm

Question:

I’m developing the Login view of my app, in order to do that I used the Django’s built-in authentication form, but when I try to validate the form it returns False and I don’t know why. I let here my code…

models.py

class User(AbstractUser):
    '''
    Model that represents a user in the database
    '''
    first_name = models.CharField(max_length=50, null=False, blank=False)
    last_name = models.CharField(max_length=50, null=False, blank=False)
    username = models.CharField(max_length=50, null=False, blank=False, unique=True)
    email = models.EmailField(null=False, blank=False, unique=True)
    password1 = models.CharField(max_length=25)
    password2 = models.CharField(max_length=25)
    birthday = models.DateField(null=False, blank=False)
    verified = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.first_name}: {self.email}'

forms.py

class AuthForm(AuthenticationForm):
    '''
    Form that uses built-in AuthenticationForm to handel user auth
    '''
    email = forms.EmailField(required=True,
        widget=forms.TextInput(attrs={
            'placeholder': 'Correo electrónico', 
            'name': 'email', 
            'type': 'email', 
            'class': 'form-control'
        }))
    password1 = forms.CharField(max_length=25, required=True,
        widget=forms.PasswordInput(attrs={
            'placeholder': 'Contraseña', 
            'name': 'password1', 
            'type': 'password', 
            'class': 'form-control'
        }))

    class Meta:
        model = User
        fields = ('email','password1', )

login.html

                            <form action="{% url 'users:login' %}" method="post">
                                {% csrf_token %}
                                <div class="mb-3">{{ form.email }}</div>
                                <div class="mb-3">{{ form.password1 }}</div>
                                <div class="mb-3"><button class="btn btn-primary shadow d-block w-100" type="submit">Iniciar sesión</button></div>
                                <p class="text-muted">Recuperar contraseña</p>
                            </form>

views.py

def login_page(request):

    if request.method == 'POST':

        form = AuthForm(request.POST)

        if form.is_valid():
            email = form.cleaned_data.get('email')
            password = form.cleaned_data.get('password1')

            user = authenticate(request, username=email, password=password)
            
            if user is not None:
                login(request, user)
                return HttpResponseRedirect(reverse('network:profile'))
            else:
                return render(request, 'users/login.html', {'form': form})
        else:
            return render(request, 'users/login.html', {'form': form})

    return render(request, 'users/login.html', {
        'form': AuthForm(),
    })

The error occurs in form.is_valid(), it returns False even when I’m sure that I’m introducing valid data to the form. Is there some error(s) in my code?, I would appreciate any help.

Asked By: Williams Jiménez

||

Answers:

I think you most use form = AuthForm(request) instead of using form = AuthForm(request.POST)
because request.POST return form method and not data to validation

Answered By: farshid mousavi

Something to consider if you’re trying to use email for authentication.

Django is expecting to see a username value in the AuthForm. You can get around this by overriding the default Auth User Model.

Ensure you’ve specified your email field as the username in your User model then follow the guide found using the link below.

Follow this guide:
https://koenwoortman.com/python-django-email-as-username/


Additionally, you’re going to have issues with using password1 and password2 as Django auth expects a password field when authenticating the user object.

I would remove password1 and password2 and just use the default password field otherwise you’ll have to override/rewrite the default authentication/password methods used by Django to reference password1 and password2 when performing a login.

Your model will then look something like this:

class User(AbstractUser):
    '''
    Model that represents a user in the database
    '''
    
    USERNAME_FIELD = 'email' # add this

    first_name = models.CharField(max_length=50, null=False, blank=False)
    last_name = models.CharField(max_length=50, null=False, blank=False)
    username = models.CharField(max_length=50, null=False, blank=False, unique=True)
    email = models.EmailField(null=False, blank=False, unique=True)
    birthday = models.DateField(null=False, blank=False)
    verified = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.first_name}: {self. Email}'

You’ll also have to replace your auth form, template and views. to use the updated fields of ’email’ and ‘password’

Be sure to migrate changes to your user model if neccessary.

Answered By: Donovan