One of the tasks that seems to come up every single project we do, is changing the auth backend to accept email addresses. Since it’s such a common task for us, it can’t be that rare to want this functionality. So, here’s a quick and simply backend which accomplishes this, using the built-in django.contrib.auth module.
from django.conf import settings from django.contrib.auth.models import User class EmailOrUsernameModelBackend(object): def authenticate(self, username=None, password=None): if '@' in username: kwargs = {'email': username} else: kwargs = {'username': username} try: user = User.objects.get(**kwargs) if user.check_password(password): return user except User.DoesNotExist: return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
Then in your settings:
AUTHENTICATION_BACKENDS = ( 'myproject.accounts.backends.EmailOrUsernameModelBackend', 'django.contrib.auth.backends.ModelBackend' )

9 Responses to "Logging In With Email Addresses in Django"
wow, it’s the piece of code i’m trying to get.
thanks for posting it, again!
Yes, Django is flexible enought to permit this just by adding this small piece of code.
One quirk arises when logging in with an email address in the admin site: if the authentication does not success for any reason you’ll get a “Usernames cannot contain the ‘@’ character.” error message which is misleading because Django is having no problem to log you in using an email address at this point.
So to correct that you should override the login() method of the admin object as pointed out by James Bennet in this bug:
http://code.djangoproject.com/ticket/8342
Antonio,
Lima - Peru
I just tried the code and realized the backend is missing the other methods that ModelBackend implements so I made EmailOrUsernameModelBackend inherint from ModelBackend instead of object and now everything works like a charm.
The code is here at PasteThat:
http://www.pastethat.com/django_email_login
Regards,
Antonio
Ya I did notice that get_user is still required. I updated the above code.
The reason it doesn’t inherit from ModelBackend is that this allows you to specify a second backend to use for permissions.
Hey, just a quick note. If using the standard login views, you won’t be able to login with an email that’s longer than 30 characters. There’s a ticket with a simple patch which hopefully will get checked in to fix that:
http://code.djangoproject.com/ticket/8274
Cheers,
Julien Phalip
> The reason it doesn’t inherit from ModelBackend is that this allows you to specify a second backend to use for permissions.
Could you expand on this? I’ve been using an EmailBackend similar to yours, except that it inherits from ModelBackend, overrides only the authenticate() method, and I use it all by itself in AUTHENTICATION_BACKENDS. This seems to work just fine. What am I missing that your approach provides?
Nice, thanks. It pleases me to find out Django allows such elegance
how do you force emails to be unique in django’s default admin? i dropped this code into my test app, and the first thing it gave me was “warning, returned 3 objects not 1!” during “User.objects.get(**kwargs)”.
@keredson
I use similar approach.
I just set the username as a slug of email replacing every weird character with _ and @ with __
Seems to work fine
@David
The only problem I have for the moment is the Admin interface to create users instead of allowing them to register…
Leave A Reply