تغيير اللغه الي العربية

My Blog


All posts

Login with username or email in Django.

we covered many things in django auth app but what if we want
to login with email instead of username ? or both?.

It's very easy to override the authenticate function to login with email or username.

if you didn't read django auth posts you can have a look at them part 1 , part 2 , part 3 , part 4 .

First we will create new file inside our users app called
backends.py
, and we will extend the Django ModelBackend and override authenticate function.

# users/backends.py

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q


UserModel = get_user_model()


class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserModel.objects.get(
Q(username__iexact=username) | Q(email__iexact=username)
)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user

I didn't came up with that code I took it from the django source code at django/contrib/auth/backends.py and just edited the query of checking the user credentials to check with email or username.



Now we need to use this in settings.py.

# settings.py
AUTHENTICATION_BACKENDS = ['users.backends.EmailBackend']

And that's it user can login with either username or email.


If you followed up with our previous posts you will see that we created a custom login form, so we will have to edit it too.

# users/forms.py
...
...

from django.db.models import Q # New

class CustomLoginForm(AuthenticationForm):
username = forms.CharField(
widget=forms.TextInput(attrs={"placeholder": "User Name Or Email"})
)
password = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={"placeholder": "Password"}),
)

def clean(self):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")

if username is not None and password:
self.user_cache = authenticate(
self.request, username=username, password=password
)
if self.user_cache is None:
try:
user = User.objects.get(
Q(username__iexact=username) | Q(email__iexact=username) # New
)
except User.DoesNotExist:
user = None
if user is not None:
if not user.is_active:
self.confirm_login_allowed(user)
else:
raise self.get_invalid_login_error()
else:
raise self.get_invalid_login_error()
else:
self.confirm_login_allowed(self.user_cache)

return self.cleaned_data

def confirm_login_allowed(self, user):
if not user.is_active:
error = "The account is closed, please contact us for more details."
raise forms.ValidationError(error)


We can also edit our RegisterForm to make email requierd in registration progress.
# users/forms.py
...
...

class RegisterForm(UserCreationForm):
def clean_email(self):
email = self.cleaned_data["email"]
if email:
match = User.objects.filter(email=email)
if match:
raise forms.ValidationError("This email address is already in use")
return email

def __init__(self, *args, **kwargs): # New
super(RegisterForm, self).__init__(*args, **kwargs)
self.fields["email"].required = True

class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")

We have clean_email function to check if email exists first, you can read Check User's Email Existence for more information.

And we are done!

I hope the tutorial was simple.
Feel free to reach out if you have any questions.


Join to discord Server Here - Django Learn Together.



Last Updated: 1 month, 1 week ago
Views: 313