Unable to authenticate Django user with email instead of username
I'm trying to implement email-based authentication in Django instead of using the default username. I’ve updated my User model and authentication backend, but I’m still unable to authenticate users with their email addresses.
views.py
from django.shortcuts import render,HttpResponseRedirect
from .forms import UserLoginForm,UserSignUpForm
from django.contrib.auth import authenticate,login,logout,get_user
from django.contrib import messages
from .models import UserRegister
# Create your views here.
def home(request):
return render(request,'home.html')
def form(request):
if request.method=="POST":
if 'login' in request.POST:
login_form = UserLoginForm(request,data=request.POST)
signup_form =UserSignUpForm()
if login_form.is_valid():
email = login_form.cleaned_data.get('email')
password = login_form.cleaned_data.get('password')
user = authenticate(request,email=email,password=password)
if user is not None:
login(request,user)
messages.success(request, "Successfully logged in!")
return HttpResponseRedirect('/home')
else:
print("Authentication Failed")
messages.error(request,"Invalid email or password")
login_form.add_error(None,"Invalid email or password")
else:
messages.error(request,"Please fix the errors below.")
print("Login form error:",login_form.errors)
print("Non-field errors:", login_form.non_field_errors())
for field in login_form:
print(f"Field Error: {field.name} - {field.errors}")
print(request.POST)
if 'signup' in request.POST:
login_form = UserLoginForm()
signup_form =UserSignUpForm(request.POST)
if signup_form.is_valid():
form_info = UserRegister(
username=signup_form.cleaned_data.get('username'),
email=signup_form.cleaned_data.get('email'),
password=signup_form.cleaned_data.get('password1')
)
form_info.save()
messages.success(request, "Successfully signup!")
return HttpResponseRedirect('/home')
else:
messages.error(request,"Please fix the errors below.")
print("Login form error:",signup_form.errors)
print("Non-field errors:", signup_form.non_field_errors())
for field in signup_form:
print(f"Field Error: {field.name} - {field.errors}")
else:
login_form = UserLoginForm()
signup_form=UserSignUpForm()
return render(request,'form.html',{'login_form':login_form,'signup_form':signup_form})
form.py
from django import forms
from django.contrib.auth.forms import UserCreationForm,AuthenticationForm
from .models import UserRegister
from django.contrib.auth import authenticate
class UserSignUpForm(UserCreationForm):
username = forms.CharField(max_length=50,required=True,widget=forms.TextInput(attrs={'id':'signup-username'}))
email = forms.EmailField(max_length=70,required=True,widget=forms.TextInput(attrs={'id':'signup-email'}))
password1 = forms.CharField(max_length=128,required=True,widget=forms.PasswordInput(attrs={'id':'signup-password1'}))
password2 = forms.CharField(max_length=128,required=True,widget=forms.PasswordInput(attrs={'id':'signup-password2'}))
class Meta:
model = UserRegister
fields = ['username','email','password1','password2']
class UserLoginForm(AuthenticationForm):
email = forms.EmailField(max_length=70, required=True, widget=forms.TextInput(attrs={'id': 'login-email'}))
password = forms.CharField(max_length=128, required=True, widget=forms.PasswordInput(attrs={'id': 'login-password'}))
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
if email and password:
self.user_cache = authenticate(request=self.request, email=email, password=password)
if self.user_cache is None:
raise forms.ValidationError("Invalid email or password")
return self.cleaned_data
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import timezone
from django.contrib.auth.hashers import make_password
class UserRegister(AbstractUser):
username = models.CharField(max_length=50,unique=True,db_index=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=128)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(default=timezone.now)
groups = models.ManyToManyField(
'auth.Group',
related_name='custom_user_groups',
blank=True,
help_text='The groups this user belongs to.'
)
user_permissions = models.ManyToManyField(
'auth.Permission',
related_name='custom_user_permissions',
blank=True,
help_text='Specific permissions for this user.'
)
class Meta:
verbose_name = "Custom User "
verbose_name_plural = "Custom Users "
def __str__(self):
return self.username
backends.py
from django.contrib.auth.backends import ModelBackend
from .models import UserRegister
class CustomAuthBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserRegister.objects.get(username=username)
if user.check_password(password):
return user
except UserRegister.DoesNotExist:
print('Unable to authenticate')
return None
def get_user(self, user_id):
try:
return UserRegister.objects.get(pk=user_id)
except UserRegister.DoesNotExist:
return None
form.html
{% extends "base.html" %}
{% block title %}
Form
{% endblock %}
{% load static %}
{% block css_files %}
<link rel="stylesheet" href="{% static 'tracker/form.css' %}">
{% endblock %}
{% block content %}
<section class="forms-section">
<h1 class="section-title">Login & Signup Forms</h1>
<div class="forms">
<div class="form-wrapper is-active">
<button type="button" class="switcher switcher-login">
Login
<span class="underline"></span>
</button>
<form class="form form-login" method="post" action="{% url 'form' %}">
{% csrf_token %}
<fieldset>
<legend>Please, enter your email and password for login.</legend>
<div class="input-block">
<label for="login-email">E-mail</label>
{{ login_form.email }}
{% if login_form.email.errors %}
<div class="error-message">
{% for error in login_form.email.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="input-block">
<label for="login-password">Password</label>
{{ login_form.password }}
{% if login_form.password.errors %}
<div class="error-message">
{% for error in login_form.password.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
</fieldset>
<button type="submit" class="btn-login" name="login">Login</button>
</form>
</div>
<div class="form-wrapper">
<button type="button" class="switcher switcher-signup">
Sign Up
<span class="underline"></span>
</button>
<form class="form form-signup" method="post" action="{% url 'form' %}">
{% csrf_token %}
<fieldset>
<legend>Please, enter your email, password and password confirmation for sign up.</legend>
<div class="input-block">
<label for="signup-username">Username</label>
{{ signup_form.username }}
{% if signup_form.username.errors %}
<div class="error-message">
{% for error in signup_form.username.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="input-block">
<label for="signup-email">E-mail</label>
{{ signup_form.email }}
{% if signup_form.email.errors %}
<div class="error-message">
{% for error in signup_form.email.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="input-block">
<label for="signup-password1">Password</label>
{{ signup_form.password1 }}
{% if signup_form.password1.errors %}
<div class="error-message">
{% for error in signup_form.password1.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="input-block">
<label for="signup-password2">Confirm Password</label>
{{ signup_form.password2 }}
{% if signup_form.password2.errors %}
<div class="error-message">
{% for error in signup_form.password2.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
</div>
</fieldset>
<button type="submit" class="btn-signup" name="signup">Sign Up</button>
</form>
</div>
</div>
</section>
<script src="{% static 'tracker/form.js' %}"></script>
{% endblock %}
error:-
Unable to authenticate
Login form error: <ul class="errorlist"><li>username<ul class="errorlist"><li>This field is required.</li></ul></li><li>__all__<ul class="errorlist nonfield"><li>Invalid email or password</li></ul></li></ul>
Non-field errors: <ul class="errorlist nonfield"><li>Invalid email or password</li></ul>
Field Error: username - <ul class="errorlist"><li>This field is required.</li></ul>
Field Error: password -
Field Error: email -
<QueryDict: {'csrfmiddlewaretoken': ['N9kPmMtMtS54Te0Ln8icxMb3UBLmhilagTu5eEPGDKr8irXGOg7qCTFdsbNozh4z'], 'email': ['jain22hardik@gmail.com'], 'password': ['hj@123456'], 'login': ['']}>
[22/Mar/2025 00:20:55] "POST /form/ HTTP/1.1" 200 4855
Here’s what I’ve tried so far:
Updated AUTH_USER_MODEL to a custom User model with EMAIL_FIELD set to email.
Customized the login form to replace username with email and included a password field.
Implemented a custom authentication backend to authenticate users using their email addresses.
Despite these changes, the login form still expects a username field and fails with the "Invalid email or password" error. How can I resolve this and fully transition to email-based authentication in Django?
Any guidance or advice would be greatly appreciated. Let me know if additional details or code snippets would help