django.contrib.auth.login does not log the user in

134 views Asked by At

I created a custom User model like the following:

class User(AbstractBaseUser):

    class Types(models.TextChoices):
        CUSTOMER = 'CUSTOMER', 'Customer'
        SUPPLIER = 'SUPPLIER', 'Supplier'
        OPERATOR = 'OPERATOR', 'Operator'

    base_type = Types.CUSTOMER

    objects = UserManager()

    phone = models.IntegerField(unique=True)
    code = models.IntegerField(blank=True, null=True)
    type = models.CharField(max_length=20, choices=Types.choices, default=base_type)
    date_joined = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    USERNAME_FIELD = 'phone'
    REQUIRED_FIELDS = []

    class Meta:
        verbose_name = 'user'
        verbose_name_plural = 'users'

    def __str__(self):
        return str(self.phone)

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    @property
    def is_staff(self):
        return self.is_admin

And a manager for the User model:

class UserManager(BaseUserManager):
    def create_user(self, phone, code=663322, password=None):
        if not phone:
            raise ValueError('Users must have a phone number')
        user = self.model(
            phone=phone,
            code=code,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, phone, code=663322, password=None):
        user = self.create_user(
            phone=phone,
            code=code,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

I wanted to have 3 different user types (customer, supplier, operator) so I created 3 profile models and having a OneToOneField to the base user model for each profile model (with some specific fields related to the user type). I also created 3 proxy models like so:

class Customer(User):
    objects = CustomerManager()
    base_type = User.Types.CUSTOMER

    class Meta:
        proxy = True

class Supplier(User):
    objects = SupplierManager()
    base_type = User.Types.SUPPLIER

    class Meta:
       proxy = True

class Operator(User):
    objects = OperatorManager()
    base_type = User.Types.OPERATOR

    class Meta:
        proxy = True

Their managers are all like this one(only get_queryset method differs):

class SupplierManager(models.Manager):
    def create(self, phone, code=223322, password=None):
        if not phone:
            raise ValueError('Users must have a phone number')

        user = self.model(
            phone=phone,
            code=code,
            type='SUPPLIER',
            )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(type='SUPPLIER')

Each user type has its own way of signing up so I made 3 different authentication backends(OperatorBackend is same as other two):

class CustomerBackend(BaseBackend):
    def authenticate(self, request, phone=None, code=None):
        if phone and code:
            try:
                user = Customer.objects.get(phone=phone)
                if user.code == code:
                    return user
                return None
            except Customer.DoesNotExist:
                return None

    def get_user(self, user_id):
        try:
            return Customer.objects.get(pk=user_id)
        except Customer.DoesNotExist:
            return None


class SupplierBackend(BaseBackend):
    def authenticate(self, request, phone=None, first_name=None):
        if phone and first_name:
            try:
                user = Supplier.objects.get(phone=phone)
                if user.sprofile.first_name == first_name:
                    return user
                return None
            except User.DoesNotExist:
                return None

    def get_user(self, user_id):
        try:
            Supplier.objects.get(pk=user_id)
        except Supplier.DoesNotExist:
            return None

And here are my views for loging users in(authenticate is django's authenticate method):

def customer_login(request):
    if request.method == 'POST':
        form = CustomerLoginForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            user = authenticate(request, phone=cd['phone'], code=cd['code'])
            if user is not None:
                login(request, user, backend='accounts.backends.CustomerBackend')
                messages.success(request, 'Logged in', 'success')
                return redirect('accounts:home')
            else:
                messages.error(request, 'User is None', 'danger')
    else:
        form = CustomerLoginForm()

    context = {
        'form': form,
    }
    return render(request, 'accounts/customer_login.html', context)


def supplier_login(request):
    if request.method == 'POST':
        form = SupplierLoginForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            user = authenticate(request, phone=cd['phone'], first_name=cd['first_name'])
            if user is not None:
                login(request, user, backend='accounts.backends.SupplierBackend')
                messages.success(request, 'Logged in', 'success')
                return redirect('accounts:home')
            else:
                messages.error(request, 'User is None', 'danger')
    else:
        form = SupplierLoginForm()

    context = {
        'form': form,
    }
    return render(request, 'accounts/supplier_login.html', context)

My problem is when I want to log in with a user type of CUSTOMER, it works and logs the user in. But when I try to log in with another user type, it doesn't work and request.user returns AnonymousUser. I have registered custom authentication backends (django's default ModelBackend is still there) and AUTH_USER_MODEL in settings.py file and auth backends does not seem to be the problem since they return the user when correct credentials are given. I tried creating new users both from admin panel and through managers, and it did not make any difference. Maybe I am going the wrong direction with this kind of implementation, I'm still new in programming. Any help is appreciated.

Edit: I tried accessing user's session_key and backend after logging in and it turns out the login function actually works. But request.user.is_authenticated returns False for some reason when using SupplierBackend.

0

There are 0 answers