如何在多对一关系中通过同一相关对象的两个属性过滤django?

时间:2017-10-12 18:55:03

标签: sql django django-models orm

我的模型结构如下所示:

class OneModel(model):
    not_important = IntegerField()


class RelatedModel():
    propertyA = IntegerField()
    propertyB = IntegerField()
    original = ForeignKey(OneModel, related_name='related')   

我正在寻找一个原生的django解决方案(没有原始的sql),基本上重新创建这个查询:

select * from OneModel om where not exists
(select id from RelatedModel rm where original_id = om.id and propertyA = 1 and propertyB = 2);

以下是我尝试的内容:

OneModel.objects.exclude(related__propertyA=1, related__propertyB=2)

不幸的是,这会产生选择OneModel对象的效果,这些对象 propertyA=1相关的对象与{{1}相关不是那些没有匹配两个标准的单一相关的人。

这是我的django查询中生成的sql:

propertyB=2

为了清楚起见,我的问题不在于使用SELECT lots_of_fields FROM "OneModel" WHERE NOT ("OneModel"."id" IN (SELECT U1."original_id" AS Col1 FROM "RelatedModel" U1 WHERE U1."PropertyA" = 1) AND "OneModel"."id" IN (SELECT U1."original_id" AS Col1 FROM "RelatedModel" U1 WHERE U1."PropertyB" = 2)) 而不是存在,而是使用查询的逻辑。

我尝试过使用Q-objects,但无法找出解决此问题的方法。我也看过F-objects,但它们似乎也不相关。有没有办法在纯django中表达这个,或者我是否有决心编写SQL?

至于为什么不只是使用SQL,我承认它更多只是因为骄傲/想要学习新东西而不是其他任何东西。

1 个答案:

答案 0 :(得分:2)

这实际上涵盖在文档中 - 它只是有点难以找到。

Here是链接:向下滚动一点到绿色 “注意”部分。

它基本上说基于外键排除有点不直观,你不能在一个查询中做到这一点。相反,这应该工作(我只是将他们的代码移植到你的名字:

query = OneModel.objects.exclude(
    related__in=RelatedModel.objects.filter(
        propertyA=1,
        propertyB=2,
    ),
)

Django优化了这一点,尽管看起来好像发生了两次查询,但实际上只有一次调用DB。如果您感到好奇,可以通过query.query检查SQL调用。