Superuser can't access Django Admin Panel. It shows "You don’t have permission to view or edit anything."

Viewed 1227

I've created a custom User model in Django==3.2.3

Here is my model.py file

class MyUserManager(BaseUserManager):
""" A custom Manager to deal with emails as unique identifer """
def _create_user(self, email, password, **extra_fields):
    """ Creates and saves a user with a given email and password"""

    if not email:
        raise ValueError("The Email 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, **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('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 User(AbstractBaseUser, PermissionsMixin):


email = models.EmailField(max_length=60, unique=True, verbose_name='Email')
first_name = models.CharField(max_length=30, verbose_name='First Name')
last_name = models.CharField(max_length=30, verbose_name='Last Name')
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ('first_name', 'last_name')

objects = MyUserManager()

def __str__(self):
    return self.email

def get_short_name(self):
    return self.first_name

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

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

class Meta:
    verbose_name_plural = "Users"

Here is my admin.py file

class MyUserAdmin(UserAdmin):
form = UserchangeForm
add_form = UserCreationForm

list_display = ('email', 'first_name', 'last_name', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
    (None, {'fields': ('email', 'password')}),
    ('Personal info', {'fields': (('first_name', 'last_name'))}),
    ('Permissions', {'fields': ('is_admin',)}),
)

add_fieldsets = (
    (None, {
        'classes': ('Wide',),
        'fields': ('email', 'first_name', 'last_name')
    }),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()


admin.site.register(User, MyUserAdmin)

After migrating and creating a superuser when I going to login into the admin panel it shows "You don’t have permission to view or edit anything."

I saw many solutions in StackOverflow and other sites. They all suggested adding has_module_perms and has_perm which I have already added.

3 Answers

The builtin user model has two fields that indicate the admin / staff status of a user, namely is_superuser and is_staff with a superuser having permission to do anything. The problem here is you have created an extra field is_admin and have also overriden has_perm, etc. (In a bad way at that) so that only a user having this field set to True would have all permissions (Other's if granted the permission still won't have it since you have overriden it that way).

You need to rename is_admin to is_superuser and also remove your has_perm and has_module_perms:

class User(AbstractBaseUser, PermissionsMixin):
    ...
    # ... is a placeholder for your code, strikethroughs mean you should remove the line
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    ...
    
    def has_perm(self, perm, obj=None):
        return self.is_admin
    
    def has_module_perms(self, app_label):
        return self.is_admin
    ...

Similarly in MyUserAdmin you have mentioned is_admin rename it to is_superuser.

Had the same issue. I then passed 'password=password' together with 'username=username' as you see below in bold into the functions and it solved the problem:

class MyAccountManager(BaseUserManager):
    def create_user(self, email, username, password):
        if not email:
            raise ValueError('Please add an email address')
        if not username:
            raise ValueError('Please add an username')

        **user = self.model(email=self.normalize_email(
            email), username=username, password=password)**

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password):
    #I have the below in my create_superuser function, I don't see it in your code:
        **user = self.create_user(email=self.normalize_email(
            email), username=username, password=password)**

Also, make sure to add AUTH_USER_MODEL = 'accounts.User' to settings.py

So this is a weird one but I hope this helps someone. The above is quite a normal way to override the Django user model, subclassing either AbstractBaseUser or AbstractUser.

But doing that, you need to create your own Admin classes which generally point either directly to the UserCreationForm and UserChangeForm, which are in the django.contrib.auth.forms module, or to a custom form that subclasses either of them.

By default, the UserCreationForm does not house the is_superuser value, which means creating an account in the admin using this form, leaves this value false - meaning you can create an account that can log in, but it doesn't yet have either explicit or implicit permission to see anything.

If you introspect the actual Form class in from django.contrib.auth.forms.UserCreationForm this is the intended behaviour, from the docstring:

"""
A form that creates a user, with no privileges, from the given username and password.
"""

For me, I could solve this in two ways:

1 - You can make sure that is_superuser is manually added to your initial UserCreationForm by making sure it's explicitly listed in your Admin class's add_fieldsets Tuple, and mine is here:

add_fieldsets = (
    (
        None,
        {
            "classes": ("wide",),
            "fields": (
                "email",
                "password1",
                "password2",
                "is_staff",
                "is_active",
                "is_superuser"
            ),
        },
    ),
)

2 - You can make sure it's manually added to the UserChangeForm by making sure it's explicitly listed in the Admin class fieldsets Tuple, which is the same thing as the above but is invoked in the ChangeForm rather than the CreationForm. You likely want to do this anyway.

Related