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.
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
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.
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.
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
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.