简体   繁体   English

Django Admin非人员访问数据过滤

[英]Django Admin Non Staff Access Data Filtering

I'm writing an application in Django (which I'm very new to) where the admin area will be exposed to 'customers' of the application, not just staff/superusers, because of the nature of the application and the way Django automatically generates forms in the admin area with such little code.. 我正在用Django(我是新手)编写一个应用程序,由于该应用程序的性质和Django自动运行的方式,管理区域将暴露给该应用程序的“客户”,而不仅仅是人员/超级用户。用很少的代码即可在管理区域中生成表单。

As such I need to robust and manageable way to maintain authentication and separating data, so only data created by a user is seen by that user. 因此,我需要一种健壮且易于管理的方式来维护身份验证和分离数据,因此该用户只能看到用户创建的数据。

At the moment I'm just using the default admin package and changing permissions for 'client users' to filter what data they can see (I only want them to see data they've created) using code like the below: 目前,我只是使用默认的管理程序包,并更改“客户端用户”的权限,以使用以下代码过滤他们可以看到的数据(我只希望他们看到他们创建的数据):

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

However as the application scales, I can see ensuring this type of data filtering becoming difficult to manage, for example if there are chains of foreign keys on certain tables( A->B B->C C->D ), and to filter the table at the end of the chain I need to do various JOIN s to get the rows which relate to the current user. 但是随着应用程序的扩展,我可以确保确保这种类型的数据过滤变得难以管理,例如,如果某些表上有外键链( A->B B->C C->D )并进行过滤在链末尾的表中,我需要执行各种JOIN来获取与当前用户相关的行。

A couple of solutions I'm pondering are creating a separate admin app per user, but this feels like overkill and even more unmanageable. 我正在考虑的几个解决方案是为每个用户创建一个单独的管理应用程序,但是这感觉有些过头了,甚至更难以管理。

Or just adding the user column to every Model where data filtering by user is required to make it easier to filter. 或者只是将用户列添加到需要按用户过滤数据的每个模型中,以使其更易于过滤。

Any thoughts on the best approach to take? 对采取最佳方法有什么想法?

First off, from experience, you're better off offering editing and creating functionality to your users in an actual django app, using View s. 首先,根据经验,您最好使用View在实际的django应用中为用户提供编辑和创建功能。 Generic views make this very easy. 通用视图使此操作非常容易。 Once you let your users into the admin, they will get used to it and it's hard to get them to leave. 一旦您让用户成为管理员,他们就会习惯了,很难离开他们。

Additionally you should use contrib.auth.Group together with django-guardian to keep track of object-level permissions instead of implementing it yourself. 另外,您应该将contrib.auth.Groupdjango-guardian结合使用以跟踪对象级权限,而不是自己实现。 It pays off in the long run. 从长远来看,它会有所回报。

If you want to make this experience on your own however, you have more than one sensible choice: 但是,如果您想自己进行这种体验,那么您有多个明智的选择:

  • owner on root objects in the ForeignKey pyramid ForeignKey金字塔中的根对象的owner
  • owner on every model 每个模型的owner

To realize the first option, you should implement two methods on every model down the ForeignKey chain: 为了实现第一种选择,您应该在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

However, as you stated, this incurrs many JOINS if your schema is sufficiently complex. 但是,正如您所述,如果您的架构足够复杂,则会产生许多JOINS

I would advise you to store the information about the owner in every model, everything else is a maintanence nightmare in my experience. 我建议您将有关所有者的信息存储在每个模型中,其他所有经验都是我梦experience以求的。

Instead of adding the field manually to every model manually, you should use inheritance. 您应该使用继承,而不是将字段手动添加到每个模型中。 However django provides bad built-in support for inheritance with relations: An abstract base model cannot define a models.ForeignKey , so you're stuck with table based inheritance. 但是django对关系的继承提供了糟糕的内置支持:抽象的基本模型无法定义models.ForeignKey ,因此您将无法使用基于表的继承。

Table based inheritance brings another problem with itself: Consider these models: 基于表的继承本身带来了另一个问题:考虑以下模型:

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)

It is easy to find the owner of a given instance of ChildA or ChildB : 这是很容易找到owner的给定实例的ChildAChildB

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

Peter 彼得

However it is non trivial to find all objects owned by a particular user: 但是,查找特定用户拥有的所有对象并非易事:

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

The default manager returns a Base object, and doesn't contain information about whether it is a ChildA or ChildB instance, which can be troublesome. 默认管理器返回一个Base对象,并且不包含有关它是ChildA实例还是ChildB实例的信息,这可能很麻烦。

To circumvent this, I recommend a polymorphic approach with django-polymorphic or django-model-utils , which is more lightweight. 为了避免这种情况,我建议使用django-polymorphicdjango-model-utils的多态方法,该方法更加轻巧。 They both provide means to retrieve the child classes for a given Base model in the queries. 它们都提供了检索查询中给定Base模型的子类的方法。 See my answer here for more information on polymorphism in django. 有关Django多态性的更多信息,请参见我的回答。

These also incur JOIN s, but at least the complexity is manageable. 这些也会引发JOIN ,但是至少复杂度是可管理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM