首页 文章

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

提问于
浏览
46

我'm starting to organize a new project and let' s说我会有一些像 productscatalogs 这样的模特 .

我将允许我的客户(不是访客,只有特定客户)登录Django Admin站点来创建,编辑和删除他们自己的目录 .

假设我创建了一个名为 "Shop" 的模型,创建每个商店(名称,地址,徽标,联系信息等)并创建一个绑定到该商店的管理员用户 .

现在我想要这个新的管理员(谁不是网站管理员,但是商店管理员 - 可能是 user group )来查看和编辑 only the catalogs linked with his shop .

那可能吗?

我应该在Django Admin中执行此操作还是应该创建一个新的“shop admin”应用程序?

4 回答

  • 58

    对不起,我知道现在已经晚了,但也许对其他人有帮助 . 我想django-permission应用程序可以帮助实现目的 .

  • 11

    首先,警告警告:Django管理员设计理念是任何有权访问管理员( is_staff==True )的用户都是受信任的用户,例如一名员工,因此"staff"甚至可以获得管理员的访问权限 . 虽然您可以自定义管理员以限制区域,但允许组织内的任何人访问您的管理员都被认为是有风险的,而Django在此时不保证任何类型的安全性 .

    现在,如果您仍想继续,您可以通过简单地不将这些权限分配给用户来限制除了商店之外的所有商品 . 您必须让所有店主有权编辑他们需要访问的任何商店模型,但其他所有商品都应该从他们的权限列表中删除 .

    然后,对于需要限制为所有者的每个模型's eyes only, you' ll需要添加一个字段来存储"owner",或者用户允许访问它 . 您可以使用 ModelAdmin 上的 save_model 方法执行此操作,该方法可以访问请求对象:

    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的查询集限制为仅当前用户拥有的那些项:

    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的易受攻击的视图以进行重定向主人:

    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)
    

    UPDATE 06/05/12

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

  • 0

    我只是在这里发帖,因为最高评论不再是最新的答案 . 我正在使用Django 1.9,我不确定这是什么时候发生了变化 .

    例如,您有不同的场地和每个场地关联的不同用户,模型将如下所示:

    class Venue(models.Model):
        user = models.ForeignKey(User)
        venue_name = models.CharField(max_length=255)
        area = models.CharField(max_length=255)
    

    现在,如果用户允许通过django管理面板登录,则该用户的员工状态必须为true .

    admin.py看起来像:

    class FilterUserAdmin(admin.ModelAdmin): 
        def save_model(self, request, obj, form, change):
            if getattr(obj, 'user', None) is None:  
                obj.user = request.user
            obj.save()
        def get_queryset(self, request):
            qs = super(FilterUserAdmin, self).queryset(request)
            if request.user.is_superuser:
                return qs
            return qs.filter(user=request.user)
        def has_change_permission(self, request, obj=None):
            if not obj:
                return True 
            return obj.user == request.user or request.user.is_superuser
    
    
    @admin.register(Venue)
    class VenueAdmin(admin.ModelAdmin):
        pass
    

    函数名称已从queryset更改为get_queryset .

    编辑:我想扩展我的答案 . 还有另一种方法可以在不使用queryset函数的情况下返回过滤的对象 . 我想强调一点,我不知道这种方法是效率更高还是效率更低 .

    get_queryset方法的另一种实现如下:

    def get_queryset(self, request):
        if request.user.is_superuser:
            return Venue.objects.all()
        else:
            return Venue.objects.filter(user=request.user)
    

    此外,我们还可以过滤内容,使关系更加深入 .

    class VenueDetails(models.Model):
        venue = models.ForeignKey(Venue)
        details = models.TextField()
    

    现在,如果我想过滤这个以Venue为外键但没有User的模型,我的查询会改变如下:

    def get_queryset(self, request):
        if request.user.is_superuser:
            return VenueDetails.objects.all()
        else:
            return VenueDetails.objects.filter(venue__user=request.user)
    

    Django ORM允许我们通过'__'访问不同类型的关系,这些关系可以达到我们想要的深度

    Here's上述官方文档的链接 .

  • 0

    我认为RelatedOnlyFieldListFilter可以帮到你 . 这里是Django Doc的链接:RelatedOnlyFieldListFilter

    list_filter可以是:一个元组,其中,所述第一元件是一个字段名称和所述第二元件是一类由django.contrib.admin.FieldListFilter继承,例如:类PersonAdmin(admin.ModelAdmin):
    list_filter =(
    ('is_staff',admin.BooleanFieldListFilter),

    您可以限制相关模型使用RelatedOnlyFieldListFilter参与这种关系的对象的选择:(VOUS pouvez限制器莱喜爱将科特迪瓦联合国MODELE谎言AUX OBJETSconcernés面值LA关系连接utilisant RelatedOnlyFieldListFilter :)类BookAdmin(admin.ModelAdmin):
    list_filter =(
    ('author',admin.RelatedOnlyFieldListFilter),

    假设作者是User模型的ForeignKey,这将把list_filter选项限制为已经写过书而不是列出所有用户的用户 . (En supposant que author estunecléOfForeignKey versunmodèleUser,cela va limiter les choix de list_filter aux utilisateurs quiontécritunlivre au lieu d'énumérertiousles utilisateurs . )

相关问题