【问题标题】:Django queryset union appears not to be working when combined with .annotate()与 .annotate() 结合使用时,Django 查询集联合似乎不起作用
【发布时间】:2018-06-10 05:41:44
【问题描述】:

我有以下查询集:

photos = Photo.objects.all()

我过滤掉了两个查询:

a = photos.filter(gallery__name='NGL')
b = photos.filter(gallery__name='NGA')

我将它们加在一起,它们形成了一个新的、更大的查询集:

c = a | b

确实a + b的长度等于c

a.count() + b.count() == c.count()
>>> True

到目前为止一切顺利。然而,如果我引入 .annotate()| 似乎不再起作用:

a = photos.annotate(c=Count('label').exclude(c__lte=4)
b = photos.filter(painting=True)
c = a | b
a.count() + b.count() == c.count()
>>> False

即使在使用.annotate() 时,如何组合查询集?请注意,查询 1 和 2 都按预期单独工作,只有在使用 | 组合它们时才会出现问题。

【问题讨论】:

  • 我相信您在 django 错误跟踪器 code.djangoproject.com/ticket/26019 上遇到了一张公开的票证
  • @Jason 好像是这样。谢谢,我找不到票了。
  • 查看差异的一种方法是检查 SQL。您可以打印在 django 中执行的查询。例如,c = a | bprint(c) 将显示 Django 生成的 SQL。然后,您可以在 shell 中运行查询并找出差异以查看为什么会发生问题。

标签: django django-queryset


【解决方案1】:

用于组合查询集的管道| 或与号& 实际上将ORAND 放入SQL 查询,因此看起来像是组合的。

one = Photo.objects.filter(id=1)
two = Photo.objects.filter(id=2)
combined = one | two

print(combined.query)
>>> ... WHERE ("photo_photo"."id" = 1 OR "photo_photo"."id" = 2)...

但是当您组合更多过滤器和排除项时,您可能会注意到它会给您带来奇怪的结果。这就是为什么在比较计数时它不匹配的原因。

如果您使用.union(),您必须拥有具有相同数据类型的相同列,因此您必须注释两个查询集。关于.union()的信息

  • .UNION() 中的 SELECT 语句必须具有相同的列数
  • 列还必须具有相似的数据类型
  • 每个 SELECT 语句中的列的顺序也必须相同

您必须记住,pythons 参数kwargs 用于不定数量的参数是字典,因此如果您想使用带有多个注释的注释,则无法确保列的正确顺序。幸运的是,您可以通过链接注释命令来解决这个问题。

 # printed query of this won't be consistent
 photo_queryset.annotate(label_count=Count('labels'), tag_count=Count('tags')) 
 # this will always have same order of columns
 photo_queryset.annotate(label_count=Count('labels')).annotate(tag_count=Count('tags'))

然后你可以使用.union(),它不会弄乱注释的结果。 .union() 也应该是最后一种方法,因为在 .union() 之后你不能使用 filter 这样的方法。如果要保留重复项,请使用.union(qs, all=True),因为.union() 具有默认all=False 并在查询集上调用DISTINCT

photos = Photo.objects.annotate(c=Count('labels'))
one = photos.exclude(c__lte=4)
two = photos.filter(painting=True)
all = one.union(two, all=True)
one.count() + two.count() == all.count()
>>> True

那么它应该像你在问题中描述的那样工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 2015-04-09
    • 2023-03-27
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多