Django Admin 非员工访问数据过滤

Django Admin Non Staff Access Data Filtering

我正在用 Django 编写一个应用程序(我对它很陌生),其中管理区域将暴露给应用程序的 'customers',而不仅仅是 staff/superusers,因为应用程序的性质以及 Django 使用如此少的代码在管理区域自动生成表单的方式..

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

目前我只是使用默认的管理包并更改 'client users' 的权限来过滤他们可以看到的数据(我只希望他们看到他们创建的数据)使用像这样的代码以下:

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()

然而,随着应用程序的扩展,我可以看到确保这种类型的数据过滤变得难以管理,例如,如果某些 tables(A->B B->C C->D),为了过滤链末尾的 table,我需要做各种 JOIN 来获取与当前用户相关的行。

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

或者只是将用户列添加到每个需要按用户过滤数据的模型中,以使其更易于过滤。

对最佳方法有什么想法吗?

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

此外,您应该使用 contrib.auth.Group together with django-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,因此您只能使用基于 table 的继承。

Table 基于继承本身带来了另一个问题:考虑这些模型:

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)

很容易找到 ChildAChildB 的给定实例的 owner:

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

彼得

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

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

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

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

这些也会产生 JOINs,但至少复杂性是可控的。