0

I'm new to django, and I have to make a back-end with it. my issue: I have multiple models (clients,driver,company) all of them should login and authenticate (each one on a diffrent app, but they all extend the same user model), i have seen so many questions like this, but none of them solved my issue which is authenticate(username='username',password='password') always return none. the user record exists in the DB, i checked it with filter(username=(username). so here is some code:

The UserManager class:

class UserManager(BaseUserManager):

def create_user(self, username, password, phone):
    if not username:
        raise ValueError("user must provide a username")
    if not password:
        raise ValueError("user must provide a password")
    if not phone:
        raise ValueError("user must povide a phone number")

    user_obj = self.model(
        user_name=username,
        phone=phone
    )
    user_obj.set_password(password)
    user_obj.save()
    return user_obj

the User class:

class User(AbstractBaseUser):
    user_name = models.CharField(max_length=32, unique=True)
    email = models.EmailField(max_length=255, unique=True, null=True)
    phone = PhoneNumberField()
    access_token = models.CharField(max_length=255, unique=True, null=True)
    notifications_token = models.CharField(max_length=255, unique=True, null=True)
    photo = models.ImageField()
    person_in_contact = models.CharField(max_length=32)
    active = models.BooleanField(default=False)
    confirmedEmail = models.BooleanField(default=False)
    confirmedPhone = models.BooleanField(default=False)
    completedProfile = models.BooleanField(default=False)

    objects = UserManager()

    @property
    def is_active(self):
        return self.active

    def __str__(self):
        return "Client : " + self.user_name + " Email:" + self.email

    def get_email(self):
        return self.email

    USERNAME_FIELD = 'user_name'

    REQUIRED_FIELDS = ['username', 'phone', 'password']

    class Meta:
        abstract = True

Person class (client and driver extends from this):

class Person(User):
    GENDER = (('F', 'FEMALE'), ('M', 'MALE'))

    name = models.CharField(max_length=50, null=True)
    surname = models.CharField(max_length=50, null=True)
    adress = models.CharField(max_length=255, null=True)
    birth_date = models.DateField(null=True)
    gender = models.CharField(max_length=1, choices=GENDER, default='M')

    def age(self):
        today = date.today()
        return today.year - self.birth_date.year

    def __str__(self):
        return super().__str__() + " Name : " + self.name

    class Meta:
        abstract = True

here is the driver model that i'm testing with (if this succeed i'll apply the same method to the 2 other models):

class Driver(Person):
    rating = models.DecimalField(default=0, decimal_places=1, max_digits=3)
    driving_license = models.CharField(max_length=50, null=True)
    insurance_number = models.CharField(max_length=50, null=True)
    company = models.ForeignKey(TransportCompany, on_delete=models.DO_NOTHING, null=True)

my settings.py folder is setup:

AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)

AUTH_USER_MODEL = 'drivers.Driver'

and here is how i test in the python console:

>>> from django.contrib.auth import authenticate
>>> print (authenticate(username='Simouchee',password='123456789'))
None

and when i test with filter and exists:

>>> driver = Driver.objects.filter(user_name = 'Simouchee')
>>> driver.exists()
True

any help/hint on how authenticate custom models properly is appreciated. really sorry for the long thread i felt the need of explaining in details.

5
  • If you retrieve the instance, does driver.check_password('123456789') return True? Commented Jul 29, 2019 at 14:11
  • 1
    How are you creating your driver in the console before you run authenticate? Commented Jul 29, 2019 at 14:18
  • @schwobaseggl yes it does return true. Commented Jul 29, 2019 at 14:21
  • @Hanny i'm not creating the driver in the console, the driver is already in the database, i'm just trying to authenticate it. Commented Jul 29, 2019 at 14:21
  • Why not just create a test (automated) - then create the user and find/diagnose the problem in the test, instead of using data in a DB that might change? Then you could create the user and try authenticating to ensure 100% it's not data-related that might be causing some issue? It's the safer way to go about it, automated and ensures you are in charge of the process all the way - also, it's reproducible for other users in the future, testable from anywhere and allows you to get your code under test for future changes so you know it doesn't break. Commented Jul 29, 2019 at 14:55

2 Answers 2

1

You have a mistake here authenticate(username='Simouchee',password='123456789')

You have user_name in your model, but username in authenticate call.

I would say, that it's preferable to have username without underscore in your model in the same fashion as in django framework itself - https://github.com/django/django/blob/master/django/contrib/auth/models.py#L299

Also check password as mentioned here - Django authenticate() always return None for a custom model

Edited: Issue can be in User model. You have default=False for field active, so check also if your user is active. Since ModelBackend checks is_active in method user_can_authenticate - https://github.com/django/django/blob/master/django/contrib/auth/backends.py#L51

Sign up to request clarification or add additional context in comments.

4 Comments

The default ModelBackend translates the standard username kwarg passed to authenticate to a query on the USERNAME_FIELD (see github.com/django/django/blob/master/django/contrib/auth/…). So the underscore should not be the problem.
@schwobaseggl is right, i did as you said, and still the same problem.
@schwobaseggl, That is true, my bad. Well i have another 1 guess thanks to your link. @wassimchaguetmi, Check please if your user is active. You have default=False for field active
omg bro, you are awsome, it worked! i thought i had to check if active or not by myself, i didn't know that django does it automatically for me. all i had to do was making the user active excplicitly in the database, and it authenticated properly and returned the user. thank you so much, edit your answer so i can accept it, so other people can benefit from it.
0

Sounds like there is no issue with your code. Django built-in function of Authenticate works perfectly, make sure if the user is created properly.

If you are using this to create a user:

user = User.objects.create(username=username, password=user_password, email=user_email)

It will create User but, it might not authenticate. It will return None, it happened with me too.

Please try this:

user = User.objects.create_user(username=username, password=user_password, email=user_email) user.save()

Then try authenticate(username=username, password=password) It should work!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.