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