Reputation: 1801
I want to create a permission (or something that achieves the same thing) that can be applied to all users optionally, including super users.
I can create a custom permission very easily:
ct = ContentType.objects.get_for_model(MyModel)
Permission.objects.create(
name='optional permission',
codename='optional_permission,
content_type=ct)
However, this will always return True for superusers user.has_perm('my_app_label.optional_permission')
My use-case is:
I'd like to create a queryset manager function that only returns Draft articles for users in Groups that have optional_permission
applied. I'd like superusers to be exempt from seeing these draft articles if they want.
Upvotes: 0
Views: 862
Reputation: 1801
I had to implement a slightly ugly workaround in the end, so would be interested to know if someone can do better.
I had to add an override boolean for superusers on our User model
class User(AbstractUser):
superuser_view_draft_override = models.BooleanField(
default=False, help_text='This allows us to toggle the \'see draft\' permission for superusers only')
@cached_property
def can_see_draft_content(self):
# Have to use the boolean override for superusers because they
# have all permissions turned on by default
if self.is_superuser:
return self.superuser_view_draft_override
# Otherwise use the permission...
return self.has_perm('my_app_label.optional_permission')
Upvotes: 0
Reputation: 3337
You could try to override has_perm
by passing an additional keyword argument to the original implementation.
class User(AbstractUser):
...
def has_perm(self, perm, obj=None, superuser_exempt=True):
# Active superusers have optional permissions.
if superuser_exempt:
if self.is_active and self.is_superuser:
return True
# Otherwise we need to check the backends.
return _user_has_perm(self, perm, obj)
Take a look of has_perm
source code:
class PermissionMixin:
def has_perm(self, perm, obj=None):
"""
Return True if the user has the specified permission. Query all
available auth backends, but return immediately if any backend returns
True. Thus, a user who has permission from a single auth backend is
assumed to have permission in general. If an object is provided, check
permissions for that object.
"""
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True
# Otherwise we need to check the backends.
return _user_has_perm(self, perm, obj)
AbstractUser
inherits has_perm
method from PermissionMixin
class AbstractUser(AbstractBaseUser, PermissionsMixin):
...
Upvotes: 2