Django Admin は、特にchange
パーミッションを扱う部分が少し粗いです。内部メソッドは、実際には不足している許可ModelAdmin.has_change_permission()
のチェックをカバーしています。view
第 2 に、行レベルのパーミッションを管理するためのGuardedModelAdmin
所有権チェック ( を介して) とフォームが提供されます。user_can_access_owned_objects_only
Django 管理者に他の行レベルのアクセス ポリシーは提供しません。
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))
このようにして、より柔軟な権限チェックを実現できます。user-permissions はグローバルになり、user-obj-permissions は行レベル ベースになります。
joe.user_permissions.add(add_task)
joe は新しいタスクを追加できます (行レベルの「追加」権限はありません)
joe.user_permissions.add(change_task)
ジョーはすべてのタスクを変更できる
joe.user_permissions.add(delete_task)
ジョーはすべてのタスクを削除できます
assign(Task._meta.get_change_permission(), joe, obj)
joe は Task obj を変更できます。obj と他の変更可能なタスクを含む変更リストを参照してください。
assign(Task._meta.get_delete_permission(), joe, obj)
joe は Task 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
変更してパッチを適用します。相対チケットは13539 & 16862 ですif not user.has_perm(p):
if not user.has_perm(p, obj):