Ad

Login Via Phone Field In Extended User Model

- 1 answer

I have used django user model and extended it to add a phone field. I was able to use either username or email to login but cannot access phone number field from extended user model.

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phonenumber = models.CharField(max_length=10)

backends.py

class AuthenticationBackend(backends.ModelBackend):
    def authenticate(self, request,  username=None, password=None, **kwargs):
        usermodel = get_user_model()
        print(usermodel)

        try:
            user = usermodel.objects.get(Q(username__iexact=username) | Q(
                email__iexact=username))
            if user.check_password(password):
                return user
        except user.DoesNotExist:
            pass

backend.py is what I used to implement login via username or email but I couldn't do it for phonenumber in extended user model.

Ad

Answer

There are two ways to solve your problem.

  1. Extend the User model by subclassing it, and changing the default User model. I would recommend you go this route, since the Phone number is used for authentication.
  2. Set related_name on Profile, and query the User model from that name.

For the first one, I recommend you check out the Django documentation on creating custom users. There is also a pretty extensive tutorial on how to do this here.

If you want to go the easy route, you just need to set a reverse accessor on the Profile's phonenumber field.

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phonenumber = models.CharField(max_length=10, related_name='profile')

You can then search users by their profile's phonenumbers:

class AuthenticationBackend(backends.ModelBackend):
    def authenticate(self, request,  username=None, password=None, **kwargs):
        usermodel = get_user_model()
        print(usermodel)

        try:
            user = usermodel.objects.get(Q(username__iexact=username) | Q(
                email__iexact=username) | Q(profile__phonenumber__iexact=username)
            if user.check_password(password):
                return user
        except user.DoesNotExist:
            pass

Although this is not within the scope of your question, I think you should be aware of the following issues with your code:

  • Phone numbers are often more complex than a 10 character string. +31 6 12345678, is a valid phone number, but it's more than 10 characters. Check out this question for pointers on how to store and validate phone numbers.
  • If you use a field for authentication, make sure it's unique. The phonenumber field should actually be phonenumber = models.CharField(max_length=10, related_name='profile', unique=True)
  • Your usermodel.objects.get(...) query will return more than one user if there is a user with phone number '0123456789' and a different user with username '0123456789'. You should constrain usernames to not contain phone numbers, which is only possible by extending the default User class.
Ad
source: stackoverflow.com
Ad