【问题标题】:Django models - pass additional information to managerDjango 模型 - 将附加信息传递给经理
【发布时间】:2009-09-23 16:44:07
【问题描述】:

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

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

items = Item.scoped.forceRule('user1').all()  # all items visible for 'user1'

# show all items of 'user2' visible by 'user1'
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') 

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

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)

对于显示的示例,它可以正常工作,但在以下情况下会死:

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

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

所以,问题是 - 有没有办法将声明 (*) 中提供给 forceRule() 的参数传递给经理,在声明 (**) 中调用。

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

谢谢。

【问题讨论】:

  • 我也面临同样的用例,我想知道你是如何解决这个问题的?谢谢!

标签: python django django-models


【解决方案1】:

从我对文档的阅读来看,我认为有两个问题:

  1. SecurityManager 不会用于相关对象(而是使用 django.db.models.Manager 的实例)
  2. 您可以解决上述问题,但文档非常棒 lengths 指定 get_query_set() 不应过滤掉任何相关查询的行。

我建议创建一个接受 QuerySet 并应用您需要的过滤器的函数。然后,只要您获得一个 QS 项目并想要进一步处理它们,就可以使用它。

【讨论】:

  • 感谢您的回答。 1. 我阅读了文档并且在items[0].author.item_set.all() Django 调用SecurityManager.get_query_set() 时非常惊讶。我没有要求他们使用 use_for_related_fields。但它是该模型的唯一经理,也许这很重要。 2. 是的,我读过它,但仍然认为这不是我的情况,因为我真的希望 Django 看到的不是所有数据库,而是它的一部分。也许,我会按照你的建议做,但我的问题不是如何过滤掉不相关的数据,而是让这种过滤尽可能简单和自动化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
相关资源
最近更新 更多