Search code examples
pythondjangodjango-authenticationdjango-login

Log in user using either email address or username in Django


I am trying to create an auth backend to allow my users to log in using either their email address or their username in Django 1.6 with a custom user model. The backend works when I log in with a user name but for some reason does not with an email. Is there something I am forgetting to do?

from django.conf import settings
from django.contrib.auth.models import User

class EmailOrUsernameModelBackend(object):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    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, username):
        try:
            return User.objects.get(pk=username)
        except User.DoesNotExist:
            return None

Edit: As suggested I have inherited from ModelBackend and installed it in my settings In my settings I have this AUTHENTICATION_BACKENDS = ( 'users.backends', 'django.contrib.auth.backends.ModelBackend', ) And I have changed the backend to this:

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.backends import ModelBackend
class EmailOrUsernameModelBackend(ModelBackend):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    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, username):
        try:
            return User.objects.get(pk=username)
        except User.DoesNotExist:
            return None

Now I get an Module "users" does not define a "backends" attribute/class error.


Solution

  • After following the advice given to me above and changing AUTHENTICATION_BACKENDS = ['yourapp.yourfile.EmailOrUsernameModelBackend'] I was getting the error Manager isn't available; User has been swapped for 'users.User'. This was caused because I was using the default User model instead of my own custom one. Here is the working code.

    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.contrib.auth.backends import ModelBackend
    
    class EmailOrUsernameModelBackend(ModelBackend):
        """
        This is a ModelBacked that allows authentication
        with either a username or an email address.
        
        """
        def authenticate(self, username=None, password=None):
            if '@' in username:
                kwargs = {'email': username}
            else:
                kwargs = {'username': username}
            try:
                user = get_user_model().objects.get(**kwargs)
                if user.check_password(password):
                    return user
            except User.DoesNotExist:
                return None
    
        def get_user(self, username):
            try:
                return get_user_model().objects.get(pk=username)
            except get_user_model().DoesNotExist:
                return None