Django管理员非员工访问数据过滤

时间:2015-10-28 12:18:49

标签: python django permissions django-admin django-permissions

我正在Django(我很新)中编写一个应用程序,其中管理区域将暴露给客户'由于应用程序的性质以及Django使用如此少的代码在管理区域自动生成表单的方式,应用程序,而不仅仅是工作人员/超级用户...

因此,我需要健壮且易于管理的方式来维护身份验证和分离数据,因此该用户只能看到用户创建的数据。

目前,我只是使用默认的管理包并更改了“客户端用户”的权限。使用以下代码过滤他们可以看到的数据(我只希望他们看到他们创建的数据):

class MyModelAdmin(admin.ModelAdmin):

    def get_queryset(self, request): 
        qs = super(MyModelAdmin, self).get_queryset(request) 
        return qs.filter(user=request.user)

    def save_model(self, request, obj, form, change):
        # field not editable in admin area so handle it here...
        obj.user = request.user
        obj.save()

然而,随着应用程序的扩展,我可以看到确保此类数据过滤变得难以管理,例如,如果某些表上存在外键链(A->B B->C {{1} }),并过滤链末尾的表我需要做各种C->D来获取与当前用户相关的行。

我正在考虑的一些解决方案是为每个用户创建一个单独的管理应用,但这感觉就像是矫枉过正,甚至更难以管理。

或者只是将用户列添加到每个需要用户进行数据过滤的模型中,以便于过滤。

对最佳方法的任何想法?

1 个答案:

答案 0 :(得分:0)

首先,根据经验,您最好使用View在实际的django应用中为用户提供编辑和创建功能。通用视图使这很容易。一旦您让用户加入管理员,他们就会习惯,并且很难让他们离开。

此外,您应该使用contrib.auth.Groupdjango-guardian来跟踪对象级权限,而不是自己实现。 从长远来看,这是值得的。

如果您想自己创造这种体验,那么您有多种明智的选择:

  • owner关于ForeignKey金字塔
  • 中的根对象 每个模特
  • owner

要实现第一个选项,您应该在ForeignKey链上的每个模型上实现两个方法:

def get_parent(self):
    """Should return the object that should be queried for ownership information"""
    pass
def owned_by(self, user):
    """Should return a boolean indicating whether `user` owns the object, by querying `self.get_parent().owned_by(user)`"""  
    pass

但是,如您所述,如果您的架构足够复杂,则会导致许多JOINS

我建议你在每个模型中存储有关所有者的信息,其他一切都是我经验中的维护噩梦。

您应该使用继承,而不是手动将字段手动添加到每个模型。但是,django通过关系为继承提供了错误的内置支持:抽象基础模型无法定义models.ForeignKey,因此您仍然坚持使用基于表的继承。

基于表的继承带来了另一个问题:考虑这些模型:

from django.db import models
from app.settings import AUTH_USER_MODEL
class Base(models.Model):
    owner = models.ForeignKey(AUTH_USER_MODEL)
class ChildA(Base):
    name = models.CharField(max_length=5)
class ChildB(Base):
    location = models.CharField(max_length=5)

很容易找到ownerChildA的给定实例的ChildB

>>> obj = ChildA.objects.create(owner=Peter, name="alex")    
>>> obj.owner

彼得

然而,找到特定用户拥有的所有对象并非易事:

>>> Base.objects.filter(owner=Peter)
<Base-object at 0xffffff>

默认管理器返回一个Base对象,并且不包含有关它是ChildA还是ChildB实例的信息,这可能很麻烦。

为了避免这种情况,我建议使用django-polymorphicdjango-model-utils的多态方法,它更轻量级。它们都提供了在查询中检索给定Base模型的子类的方法。 有关django中多态性的更多信息,请参阅我的答案。

这些也会导致JOIN,但至少复杂性是可控制的。