在Django中创建权限,可以选择将其应用于超级用户

问题描述

我想创建一个权限(或实现相同目的的权限),该权限可以有选择地应用于所有用户包括超级用户

我可以很容易地创建自定义权限:

ct = ContentType.objects.get_for_model(MyModel)
Permission.objects.create(
        name='optional permission',codename='optional_permission,content_type=ct)

但是,对于超级用户user.has_perm('my_app_label.optional_permission')

,它将始终返回True。

我的用例是: 我想创建一个查询集管理器函数,该函数仅为已应用optional_permission的组中的用户返回草稿文章。我希望超级用户可以免去看这些草稿的要求。

解决方法

您可以尝试通过向原始实现中传递一个额外的关键字参数来覆盖has_perm

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,obj)

看看has_perm源代码:

class PermissionMixin:
    def has_perm(self,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,obj)

AbstractUserhas_perm继承了PermissionMixin方法

class AbstractUser(AbstractBaseUser,PermissionsMixin):
    ...
,

最后我不得不实施一个稍微丑陋的解决方法,因此有兴趣知道某人是否可以做得更好。

我必须在用户模型上为超级用户添加一个覆盖布尔值

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')