如何将Model.objects.all()限制为与一个组织有关的数据

时间:2017-12-04 20:08:27

标签: python django multithreading django-models django-managers

我正在开发一个将存储多个Organizations的Web应用程序,其中每个组织都有自己的用户。组织由domainCharField)标识,用户只能查看与其自己的组织相关的数据。出于简单性和性能原因,我将所有组织的数据存储在同一个数据库中,而不是创建N个数据库/视图。

我想要实现的是一种在用户请求的上下文中,通过相关domain限制查询的简单方法。

我尝试了什么

过滤所有查询集

由于每个用户都属于某个组织,因此首先想到的选项是使用以这种方式定义的queryset

queryset = MyModel.objects.all(domain=request.user.domain)

我无法使用此解决方案,因为它会强制开发人员在Web应用程序周围手动过滤所有查询。如果有人忘记正确过滤查询集,则组织用户可以查看其他组织的数据。这很容易出错。

线程本地

因为我可以在请求中找到用户。另一种解决方案是通过中间件公开请求,并使用将执行请求的用户的域自动按域过滤。为此我发现了question,但意见分歧很大。

我仍然需要弄清楚为什么使用线程本地是一个糟糕的选择。我在Freenode / #django上讨论了这一点,但没有人扩大避免它的原因。我想更好地了解什么是专业人士和专业人士。这个解决方案的缺点。

模型mixins

我想要一个mixin(比如说DomainModelMixin)来设置两个经理:

objects = DomainManager()
super_objects = models.Manager()

super_objects是默认管理员(未经过滤),objects是按域过滤的自定义管理器,仅提供与组织相关的数据。

问题是在模型层我们没有请求,因此我们没有User,我们不知道将domain限制为查询集。我们如何将domain传递给经理?

最大的问题

我们如何以透明且易于开发人员使用的方式自动过滤objects.all()?如果我们想从没有Request对象的上下文(例如交互式shell或测试)中使用相同的逻辑,该怎么办?

1 个答案:

答案 0 :(得分:1)

我也希望用Django管理器解决这个问题,这是解决问题的最惯用的方法,但是在模型层缺少请求信息使它不合适。

相反,我认为使它更不容易出错的最好方法是在模型中简单地定义一个函数,并在可以动态化的地方调用它。 我假设您的用户正在扩展Django用户。

.related-posts .related-thumb {
    width: 100%!important;
    height: 100%!important;
    position: relative;
    overflow: hidden;
    display: block;
}

如果您有几种类型的自定义用户,则还可以在其中使用一些鸭子类型,只需为每种类型实现相关的domains()函数,它将为您提供经过适当过滤的查询集。 不要忘记查询集是懒惰的,因此您可以从视图中添加更多过滤器。