Django Admin,特别是它处理 w/change权限,有点粗粒度。内部方法ModelAdmin.has_change_permission()涵盖了view实际缺乏的权限检查。
其次,GuardedModelAdmin带来了所有权检查(通过user_can_access_owned_objects_only)和用于管理行级权限的表单。它不向 Django Admin 提供任何其他行级访问策略。
对于 Django Admin 中典型的行级权限场景,我想建议代码,这里我引入了一个可选的“查看”权限:
class ExtendedGuardedModelAdmin(GuardedModelAdmin):
    def queryset(self, request):
        qs = super(ExtendedGuardedModelAdmin, self).queryset(request)
        # Check global permission
        if super(ExtendedGuardedModelAdmin, self).has_change_permission(request) \
            or (not self.list_editable and self.has_view_permission(request)):
                return qs
        # No global, filter by row-level permissions. also use view permission if the changelist is not editable
        if self.list_editable:
            return get_objects_for_user(request.user, [self.opts.get_change_permission()], qs)
        else:
            return get_objects_for_user(request.user, [self.opts.get_change_permission(), self.get_view_permission(
)], qs, any_perm=True)
    def has_change_permission(self, request, obj=None):
        if super(ExtendedGuardedModelAdmin, self).has_change_permission(request, obj):
            return True
        if obj is None:
            # Here check global 'view' permission or if there is any changeable items
            return self.has_view_permission(request) or self.queryset(request).exists()
        else:
            # Row-level checking
            return request.user.has_perm(self.opts.get_change_permission(), obj)
    def get_view_permission(self):
        return 'view_%s' % self.opts.object_name.lower()
    def has_view_permission(self, request, obj=None):
        return request.user.has_perm(self.opts.app_label + '.' + self.get_view_permission(), obj)
    def has_delete_permission(self, request, obj=None):
        return super(ExtendedGuardedModelAdmin, self).has_delete_permission(request, obj) \
                or (obj is not None and request.user.has_perm(self.opts.get_delete_permission(), obj))
这样,您可以实现更灵活的权限检查,用户权限现在是全局的,用户对象权限是基于行级的:
- joe.user_permissions.add(add_task)
 joe 可以添加新任务(没有行级“添加”权限)
- joe.user_permissions.add(change_task)
 乔可以改变所有的任务
- joe.user_permissions.add(delete_task)
 joe 可以删除所有任务
- assign(Task._meta.get_change_permission(), joe, obj)
 joe 可以更改 Task obj,查看包含 obj 的更改列表以及其他可更改的任务。
- assign(Task._meta.get_delete_permission(), joe, obj)
 joe 可以删除任务 obj
- assign('view_task', joe, obj)
 [可选] joe 可以查看任务 obj(您可能希望在自定义管理视图页面检查此权限)
- joe.user_permissions.add(Permission.objects.get(codename='view_task', ...))
 [可选] joe 可以查看更改列表中的所有任务,只要更改列表不可内联编辑。如果 joe 可以在没有更改权限的情况下从 raw_id_fields 中获取项目,这将很有用。
- ...
如果它对您没用,您可以安全地忽略“查看”权限。
目前,django.contrib.admin.util.get_deleted_objects在检查权限时不尊重 obj,如果您需要在删除时检查行级权限,请将行get_deleted_objects修改if not user.has_perm(p):为if not user.has_perm(p, obj):. 相关票是13539 & 16862