mirolim-dev / Learn-DRF

I'm gonna upload several projects in this repo
Apache License 2.0
0 stars 0 forks source link

I can't Login to my django admin panel with my staff user #1

Closed mirolim-dev closed 1 year ago

mirolim-dev commented 1 year ago

Note! I'm entering exact data belong to that user and I already set AUTH_USER_MODEL in my settings.py file

Extra description:

_I got Custom User model I'm changing user's staff_status by django signal after Adminstrator, Boss and Teacher models Created_

Code examples:

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

class CustomUserManager(BaseUserManager):

    def create_user(self, email, password=None, **extra_fields):
          if not email:
              raise ValueError('The Email field must be set')
          email = self.normalize_email(email)
          user = self.model(email=email, **extra_fields)
          user.set_password(password)
          user.save(using=self._db)
          return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True')

        return self.create_user(email, password, **extra_fields)

class CustomUser(AbstractBaseUser, PermissionsMixin):

    username = models.CharField(max_length=255, unique=True)
    first_name = models.CharField(max_length=255, blank=True)
    last_name = models.CharField(max_length=255, blank=True)
    email = models.EmailField(unique=True)
    password = models.CharField(max_length=255)
    phone = models.CharField(max_length=20)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    objects = CustomUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    def get_full_name(self):
        return f"{self.first_name} {self.last_name}"

    def get_short_name(self):
        return self.first_name

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

    def has_module_perms(self, app_label):
        return super().has_module_perms(app_label)

    def get_user_type(self):
        # add your implementation here
        return []

    def __str__(self):
        return self.email

class Boss(models.Model):

    class Meta:
        verbose_name_plural = "Bosses"
        ordering = ['-created_at']    

    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
    salary = models.DecimalField(max_digits=15, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user}"

    def calculate_kpi(self):
        pass

class Adminstrator(models.Model):

    class Meta:
        verbose_name_plural = 'Admintrators'
        ordering = ['-created_at']

    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
    salary = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self) -> str:
        return f"{self.user}"

    def calculate_kpi(self):
        pass

class Teacher(models.Model):

    class Meta:
        verbose_name_plural = 'Teachers'
        ordering = ['-created_at']
        # permissions = (
        #     ('can_view_attandance', "Can view attandance"),
        #     ('can_add_attandance', 'Can add attandance'),
        #     ('can_change_attandance', 'Can change attandance'),
        #     )

    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
    salary = models.DecimalField(max_digits=10, decimal_places=2)
    subjects = models.ManyToManyField(Subject)
    created_at = models.DateTimeField(auto_now_add=True, editable=False)

    def __str__(self) -> str:
        return f"{self.user}"

# signals here

from django.dispatch import receiver

from django.db.models.signals import post_save
from django.contrib.auth.models import Permission
from .variables import employees_permissions```

@receiver(post_save, sender=Boss)
@receiver(post_save, sender=Teacher)
@receiver(post_save, sender=Adminstrator)
def change_user_staff_status(sender, instance, created, **kwargs):
    """Grant access to Django's admin dashboard for new employees."""
    if created and hasattr(instance, 'user'):
        user = instance.user
        model_name = instance.__class__.__name__.lower()
        print(f"Model name: {model_name}")
        permissions = employees_permissions.get(model_name)
        print(f"Perms: {permissions}")
        permission_ids = []
        for codename, name in permissions:
            # print(name)
            permission = tuple(set(Permission.objects.filter(name=name)))
            print(f"Perm: ",permission)
            if len(permission) > 1:
                for pr in permission:
                    permission_ids.append(pr.id)
                else:
                    permission_ids.append(permission[0].id)
            # permission = Permission.objects.filter(name=name)
        print(permission_ids)

        user.user_permissions.add(*permission_ids)
        user.is_staff = True
        user.save()
mirolim-dev commented 1 year ago

Finaly I solved this isue

I did it by changing my admin.py I gave form to add and change CustomUser. Because when I add new user by admin dashboard the old one wasn't save the password by hashing . That's whay The error was occuring while unhashing password and I wasn't be able to login to my Admin dashboard by staff user

Before I solve the isue CustomUser's admin form was like this šŸ‘‡šŸ‘‡šŸ‘‡

from django.contrib import admin
from .models import CustomUser, Subject, Room

class UserAdmin(admin.ModelAdmin):
    list_display = ['id', 'username', 'first_name', 'last_name', 'email', 'is_active', 'is_staff', 'is_superuser']
admin.site.register(CustomUser, UserAdmin)    

I was be able to solve this isue by changing it to this šŸ‘‡šŸ‘‡šŸ‘‡ After chaning

from django.contrib import admin
from .models import CustomUser, Subject, Room
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

# Register your models here.

class CustomUserAdmin(UserAdmin):
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('username', 'first_name', 'last_name', 'phone')}),
        ('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
        ('Important dates', {'fields': ('last_login',)}),
    )
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'username', 'password1', 'password2'),
        }),
    )
    add_form = UserCreationForm
    form = UserChangeForm
    model = CustomUser
    list_display = ('email', 'username', 'is_staff', 'is_superuser')
    list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
    search_fields = ('email', 'username', 'first_name', 'last_name')
    ordering = ('email',)

admin.site.register(CustomUser, CustomUserAdmin)