Django - Can't login into admin site with user create directly from admit site

567 views Asked by At

So, i have created a Customer user model using AbstractUser

Model.py

class Department(models.Model):
    department_name = models.CharField(max_length=20)

    def __str__(self):
        return self.department_name


class Role(models.Model):
    role_name = models.CharField(max_length=120)

    def __str__(self):
        return self.role_name

class Task(models.Model):
    task_desp = models.TextField(max_length=100)
    in_progress = models.BooleanField()
    
    def __str__(self):
        return self.task_desp

class Employee(AbstractUser):
    username = None
    email = models.EmailField(max_length=100,unique=True)
    phone_number = models.CharField(max_length=14)
    department = models.ForeignKey(Department,on_delete=models.CASCADE,null=True,blank=True)
    role = models.ForeignKey(Role,on_delete=models.CASCADE,null=True,blank=True)
    address = models.TextField(max_length=200)
    task_assigned = models.ForeignKey(Task,on_delete=models.CASCADE,null=True,blank=True)

    USERNAME_FIELD= 'email'
    REQUIRED_FIELDS = ['phone_number']

    objects= UserManager()

    def __str__(self):
        return self.email

manager.py

from django.contrib.auth.base_user import BaseUserManager 

class UserManager(BaseUserManager):

    use_in_migrations = True

    def create_user(self,email,password=None,**extra_fields):
        if not email:
            raise ValueError("Please provide email")

        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,**extra_fields):
        extra_fields.setdefault('is_staff',True)
        extra_fields.setdefault('is_superuser',True)
        extra_fields.setdefault('is_active',True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError("super user must have staff user")

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

Added the model in setting

AUTH_USER_MODEL = 'emp.Employee'

So,I have made 3 user via python manage.py createsuperuser and was able to login into admit site, but when I made a 4th user directly from admin site, gave it all staff and superuser permission I am not able to login

I get this error

Please enter the correct email and password for a staff account. Note that both fields may be case-sensitive.

enter image description here

I create this Elon user ( ignore the name ) directly from the admin panel but I am not able to log in with the email and password provided despite I have checked staff and superuser options. I think the password which is being shown direct maybe the issue because for the other 3 users the password is encrypted.

2

There are 2 answers

2
Maxim Danilov On

ModelAdmin saves 'password' directly, not the hash. You should do yourself on the save_model method in ModelAdmin:

@admin.site.register(Employee)
class EmployeeModelAdmin(ModelAdmin):

    ... # your model admin code

    def save_model(self, request, obj, form, change):
        if not change:
            obj.set_password(form.cleaned_data['password'])
        super().model_save(request, obj, form, change)
0
Gucci On

Yes it is true. I also faced the issue you raised when I implemented a custom user model using AbstractUser and created a user on the admin site. What I did is almost similar to what Maxim did. I added this method to the custom user class to override the default save method

def save(self, *args, **kwargs):
    if not self.pk: 
        self.set_password(self.password)
    super().save(*args, **kwargs)

The method saves a new user with an encrypted password. If you want it to work even for updating passwords, you can do away with the 'if not self.pk' argument.

EDIT:

The method I suggested here but it has one downside. When you create a user using the createsuperuser method in console, you will not be able to login if the abstract user class is your auth_model. This is because the createsuperuser method uses a create_user method which hashes the password, before it is hashed again by the abstract class. So to mitigate this, use the below code for overriding the save method. In essence, it checks it the password is already hashed, if so, it saves it as it is, if not then the hashing occurs in the abstract user class.

    def save(self, *args, **kwargs):
        if not self.pk:  # New instance
            if not self.has_usable_password():  # Check if the password is already hashed
                self.set_password(self.password)
        else:  # Existing instance, check if password has changed
            old_user = CustomUser.objects.get(pk=self.pk)
            if old_user.password != self.password:
                self.set_password(self.password)

        super().save(*args, **kwargs)