如何通过多对一关系中同一相关对象的两个属性在 django 中进行过滤?
Posted
技术标签:
【中文标题】如何通过多对一关系中同一相关对象的两个属性在 django 中进行过滤?【英文标题】:How to filter in django by two properties of the same related object in a many-to-one relationship? 【发布时间】:2017-10-12 18:55:03 【问题描述】:我的模型结构如下所示:
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
相关,也不与propertyB=2
相关,而不是不相关的对象'没有与两个条件匹配的单个相关。
这是我的 django 查询生成的 sql:
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))
为了清楚起见,我的问题不在于使用 "id" in
而不是存在,而是在于查询的逻辑。
我尝试过使用 Q 对象,但想不出任何方法来解决这个问题。我还查看了 F 对象,但它们似乎也不相关。有什么方法可以在纯 django 中表达这一点,还是我有决心编写 SQL?
至于为什么不只使用 SQL,我承认这更多是因为自豪/想要学习新事物而不是其他任何东西。
【问题讨论】:
【参考方案1】:这实际上在文档中有所介绍——只是有点难找。
Here 是链接:向下滚动一点到绿色 “注释”部分。
它本质上是说基于外键的排除有点不直观,你不能在一个查询中做到这一点。相反,这应该可行(我只是将他们的代码移植到你的名字:
query = OneModel.objects.exclude(
related__in=RelatedModel.objects.filter(
propertyA=1,
propertyB=2,
),
)
Django 对此进行了优化,虽然看起来好像发生了两个查询,但实际上只调用了一次数据库。感兴趣的可以通过query.query
查看这个SQL调用。
【讨论】:
这看起来正是我想要的。明天我会检查并标记为已接受。谢谢。以上是关于如何通过多对一关系中同一相关对象的两个属性在 django 中进行过滤?的主要内容,如果未能解决你的问题,请参考以下文章