当与.annotate()结合使用时,Django queryset union似乎不起作用

时间:2017-12-29 21:01:22

标签: django django-queryset

我有以下查询集

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(),|似乎不再起作用。

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

即使正在使用.annotate(),我如何组合查询集?请注意,只有在使用|组合它们时,查询一和二都是按预期工作的,这似乎是错误的。

1 个答案:

答案 0 :(得分:1)

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

AND

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

如果使用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()中的SELECT语句必须具有相同的列数
  •   
  • 这些列还必须具有相似的数据类型
  •   
  • 每个SELECT语句中的列也必须顺序相同
  •   

您必须记住,不确定数量的pythons参数.union()是字典,因此,如果要对多个注释使用注释,则无法确保列的正确顺序。您可以通过链接注释命令解决此问题。

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

然后它应该像您所描述的那样工作