Django模型 - 将其他信息传递给经理

8 python django django-models

我正在尝试为Django模型实现基于行的安全检查.我的想法是,当我访问模型管理器时,我指定了一些在数据库查询中使用的附加信息,以便只从数据库中获取允许的实例.

例如,我们可以有两个模型:用户,比如项目.每个项目属于一些用户,用户可能连接到许多项目.并且存在一些限制,根据这些限制,用户可能看到或看不到另一个用户的项目.我想将此限制与其他查询元素分开,并编写如下内容:

items = Item.scoped.forceRule('user1').all()  # all items visible for 'user1'
Run Code Online (Sandbox Code Playgroud)

要么

# show all items of 'user2' visible by 'user1'
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') 
Run Code Online (Sandbox Code Playgroud)

为了实现这一点,我做了以下:

class SecurityManager(models.Manager):

    def forceRule(self, onBehalf) :
        modelSecurityScope = getattr(self.model, 'securityScope', None)
        if modelSecurityScope :
            return super(SecurityManager, self).get_query_set().filter(self.model.securityScope(onBehalf))
        else :
            return super(SecurityManager, self).get_query_set()

    def get_query_set(self) :
        #
        # I need to know that 'onBehalf' parameter here
        #  
        return super(SecurityManager, self).get_query_set()

class User(models.Model) :
    username = models.CharField(max_length=32, unique=True)

class Item(models.Model) :
    author = models.ForeignKey(User)
    private = models.BooleanField()
    name = models.CharField(max_length=32)

    scoped = SecurityManager()

    @staticmethod
    def securityScope(onBehalf) :
        return Q(author__username__exact = onBehalf) | Q(bookmark__private__exact = False)
Run Code Online (Sandbox Code Playgroud)

对于显示的示例,它工作正常,但死于以下:

items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*)
items2 = items[0].author.item_set.all()  # (**)
Run Code Online (Sandbox Code Playgroud)

当然,items2由'user2'的所有项目填充,而不仅仅是那些符合规则的项目.这是因为当执行all()时SecurityManager.get_query_set()没有关于限制集的信息.虽然可以.例如,在forceRule()中,我可以为每个实例添加一个字段,然后,如果我可以从manager访问该字段,则应用所需的规则.

所以,问题是 - 有没有办法将forceRule()语句中提供的参数传递(*)给manager,在语句中调用(**).

或者另一个问题 - 我做的是一些我不应该做的奇怪事情吗?

谢谢.

小智 4

通过阅读文档,我认为存在两个问题:

  1. SecurityManager 将不会用于相关对象(并且将使用 django.db.models.Manager 的实例)
  2. 您可以修复上述问题,但文档竭尽全力指定get_query_set() 不应过滤掉相关查询的任何行。

我建议创建一个函数,该函数接受 QuerySet 并将您需要的过滤器应用于它。然后,每当您到达项目的 QS 并想要进一步处理它们时,就可以使用它。