【问题标题】:How to filter a django OR query correctly如何正确过滤 django OR 查询
【发布时间】:2021-06-17 18:15:11
【问题描述】:

我尝试使用 django q 进行 OR 查询。但是在单个查询中过滤的结果数量不同:

//result is 7
len(Project.objects.filter(Q(moderator='A') | Q(participant='B')))

//result is 6
len(Project.objects.filter(Q(moderator='A')))

//result is 0
len(Project.objects.filter(Q(participant='B')))

由于第三个查询响应一个空查询集,我希望第一个和第二个查询的结果相同。这里有什么问题?

如果我这样做,我会得到相同的结果:

//len is 6
q1 = Project.objects.filter(Q(moderator='A'))

//len is 0
q2 = Project.objects.filter(Q(participant='B'))

//len is 7
q1 | q2

我可以用 distinct() 解决这个问题。但是 querset 为 0 的合并如何产生比以前更多的结果呢?

【问题讨论】:

  • moderatorparticipant 是多对多字段吗?
  • 你能发布你的项目模型吗

标签: python django django-queryset q


【解决方案1】:

如果moderatorparticipant 都是ManyToManyFields,则会发生这种情况,在这种情况下,它将生成两个LEFT OUTER JOINs,因此Project 对象将针对每个匹配的记录重复。

我们可以使用.distinct() [Django-doc] 来防止多次返回相同的Project

len(Project.objects.filter(
    Q(moderator='A') | Q(participant='B')
).distinct())

也可以使用.count() [Django-doc]在数据库端进行计数,比在Django/Python层进行计数效率更高:

Project.objects.filter(
    Q(moderator='A') | Q(participant='B')
).distinct().count()

【讨论】:

  • 没错,都是ManyToMany字段。但我仍然明白为什么会发生这种情况。我需要考虑一下。到目前为止,谢谢。
  • @Gunter:因为它生成了一个LEFT OUTER JOIN,这意味着如果没有等于B的参与者,它仍然会创建一个B对象为NULL的行,因此,即使没有匹配项,我们也会额外计算一个。
猜你喜欢
  • 2010-10-18
  • 2020-08-29
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
相关资源
最近更新 更多