且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Django Admin - 特定用户(admin)内容

更新时间:2023-11-30 16:23:28

首先,警告:Django admin 的设计理念是任何用户都可以访问 admin (is_staff==True)是一个可信用户,例如一名员工,因此被称为员工",甚至可以访问管理员.虽然您可以自定义管理员以限制区域,但允许组织外的任何人访问您的管理员被认为是有风险的,并且 Django 在这一点上不保证任何类型的安全.

First, the cautionary warning: The Django admin design philosophy is that any user with access to the admin (is_staff==True) is a trusted user, e.g. an employee, hence the "staff" designation to even gain access to the admin. While you can customize the admin to restrict areas, allowing anyone not within your organization access to your admin is considered risky, and Django makes no guarantees about any sort of security at that point.

现在,如果您仍想继续,您可以通过简单地不将这些权限分配给用户来立即限制除商店以外的大多数内容.您必须授予所有商店所有者编辑他们需要访问的任何商店模型的权限,但其他所有内容都应从他们的权限列表中删除.

Now, if you still want to proceed, you can restrict most everything but the shops right off the bat by simply not assigning those privileges to the user. You'll have to give all the shop owners rights to edit any of the shop models they'll need access to, but everything else should be left off their permissions list.

然后,对于需要仅限所有者查看的每个模型,您需要添加一个字段来存储所有者"或用户允许访问它的信息.您可以使用 ModelAdmin 上的 save_model 方法执行此操作,该方法可以访问请求对象:

Then, for each model that needs to be limited to the owner's eyes only, you'll need to add a field to store the "owner", or user allowed access to it. You can do this with the save_model method on ModelAdmin, which has access to the request object:

class MyModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super(MyModelAdmin, self).save_model(request, obj, form, change)

然后您还需要将 ModelAdmin 的查询集限制为当前用户拥有的那些项目:

Then you'll also need to limit the ModelAdmin's queryset to only those items own by the current user:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(owner=request.user)

然而,这只会限制列出的内容,用户仍然可以使用 URL 来访问他们无权访问的其他对象,因此您需要覆盖 ModelAdmin 的每个易受攻击的视图以重定向用户不是所有者:

However, that will only limit what gets listed, the user could still play with the URL to access other objects they don't have access to, so you'll need to override each of the ModelAdmin's vulnerable views to redirect if the user is not the owner:

from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

class MyModelAdmin(admin.ModelAdmin):
    def change_view(self, request, object_id, form_url='', extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).change_view(request, object_id, form_url, extra_context)

    def delete_view(self, request, object_id, extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).delete_view(request, object_id, extra_context)

    def history_view(self, request, object_id, extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).history_view(request, object_id, extra_context)

更新 06/05/12

感谢@christophe31 指出由于ModelAdmin 的queryset 已经被用户限制,你可以在更改中使用self.queryset(),删除和历史视图.这很好地抽象了模型类名,使代码不那么脆弱.我也改为使用 filterexists 而不是 try...except 块和 get.这种方式更加精简,实际上也会产生更简单的查询.

Thanks @christophe31 for pointing out that since the ModelAdmin's queryset is already limited by user, you can just use self.queryset() in the change, delete and history views. This nicely abstracts away the model classname making the code less fragile. I've also changed to using filter and exists instead of a try...except block with get. It's more streamlined that way, and actually results in a simpler query, as well.