I am trying to create an api endpoint that lists all the users in the database, but I only want staff members to be able to do this. By default when a secretary is created, the is_staff
field in the users model is set to True
. In the permission class, I am checking to see if this field is set to true and grant permissions accordingly.
Since I have many different types of users with slightly different attributes, I created a concrete base user model that is inherited by other user models. The SECRETARY
role is assigned by the serializer when handling the secretary creation endpoint request.
class User(AbstractBaseUser):
class Roles(models.TextChoices):
"""define the user roles"""
ADMIN = "ADMIN", "Admin"
PRINTER = "PRINTER", "Printer"
SECRETARY = "SECRETARY", "Secretary"
PHOTOGRAPHER = "PHOTOGRAPHER", "Photographer"
EDITOR = "EDITOR", "Editor"
CLIENT = "CLIENT", "Client"
SYSTEM = "SYSTEM", "System"
APPLICANT = "APPLICANT", "Applicant"
id = models.CharField(
max_length=8, unique=True, primary_key=True, default=uidgen, editable=False
)
first_name = models.CharField("First Name", max_length=30, null=False)
last_name = models.CharField("Last Name", max_length=30, null=True, blank=True)
email = models.EmailField(
verbose_name="Email", max_length=255, unique=True, null=False
)
username = None
phone_number = models.CharField(
"Phone Number", max_length=20, null=False, unique=True
)
dob = models.DateField(verbose_name="Date Of Birth", blank=True, null=True)
role = models.CharField(max_length=50, default=Roles.CLIENT)
date_joined = models.DateTimeField(verbose_name="Date Joined", auto_now_add=True)
last_login = models.DateTimeField(verbose_name="Last Login", auto_now=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["phone_number"]
is_staff = False
is_superuser = False
is_active = True
is_contractor = False
is_associate = False
phone_is_verified = False
email_is_verified = False
objects = UserManager()
User manager:
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email must be set")
user = self.model(
email=self.normalize_email(email),
)
if password:
user.set_password(password)
try:
if user.role == User.Roles.SECRETARY:
extra_fields.setdefault("is_staff", True)
else:
extra_fields.setdefault("is_staff", False)
except AttributeError:
user.role = User.Roles.ADMIN
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
admin_user = self.create_user(email, password, **extra_fields)
admin_user.role = User.Roles.ADMIN
admin_user.save()
return admin_user
The Secretary model:
class Secretary(User):
bank_number = models.CharField(max_length=50, null=True)
is_staff = True
class Meta:
verbose_name = "Secretary"
verbose_name_plural = "Secretaries"
def __str__(self):
return f"{self.first_name} {self.last_name}"
objects = UserManager()
Permission class:
class UserListPermission(permissions.BasePermission):
def has_permission(self, request, view):
print(request.user.is_staff)
if view.action == "list" and request.user.is_staff:
return True
return False
def has_object_permission(self, request, view):
if view.action == "list" and request.user.is_staff:
return True
return False
I created a secretary along with an access token and tried accessing a staff only api endpoint. I get a response:
{
"detail": "You do not have permission to perform this action."
}
In the server shell output, the print statement spits out False
. In the django shell:
>>> sec = Secretary.objects.get(email='dinoseca@yahoo.de')
>>> sec.role
'SECRETARY'
>>> sec.is_staff
True
When I remove is_staff = True
from the Secretary model, the above shell snippet results in False
I feel like the mistake lies somewhere in my UserManager or my User model.