【问题标题】:Calculate intersection of two Django queries: one aggregate, another - simple计算两个 Django 查询的交集:一个聚合,另一个 - 简单
【发布时间】:2020-05-13 09:20:36
【问题描述】:

我有一个模型VariantTag,它存储了另一个模型SavedVariant 的ids。前者有另一个variant_tag_type_id 指向它的相关模型类型VariantTagType。现在我正在尝试获取所有具有only one variant_tag_type.name = 'Review' 标签的SavedVariant ids。为了让事情更清楚,这是我在 Django 中尝试做的事情:

    # Variants with just only one tag present                                                                          
    single_variant_ids = VariantTag.objects.values_list('saved_variant_id', flat=True) \                               
            .annotate(id_count=Count('saved_variant_id')).filter(id_count=1)                                           
    # All variants that have 'Review' tag                                                                              
    review_all_variant_ids = VariantTag.objects.filter(variant_tag_type__name='Review') \                              
            .values_list('saved_variant_id', flat=True)                                                                
    # Intersection of the previous two queries                                                                         
    review_variant_ids = single_variant_ids.intersection(review_all_variant_ids)

这不起作用给我一个错误:

ProgrammingError:每个 INTERSECT 查询的列数必须相同 第 1 行:...nttag"."saved_variant_id") = 1) INTERSECT (SELECT "seqr_vari...

我如何在Django 中编写这样的查询?

更新

我使用了Omar 的建议,并且能够通过像这样重写第二个查询来消除错误:

review_all_variant_ids = VariantTag.objects.filter(variant_tag_type__name='Review') \                              
                .values_list('saved_variant_id', flat=True).annotate(val=Value(0, output_field=IntegerField()))  

但是,intersection 不能正确计算交集,而只是返回空的 QuerySet。我检查了 QuerySets 将它们转换为 python lists 并将它们打印出来,这就是我所看到的:

single_variant_ids: [46, 28, 38, 30, 33, 29, 47, 31, 44]
review_all_variant_ids: [22, 36, 46, 47]
review_variant_ids: []

如您所见,交集结果不应为空,而应为 QuerySet,其值为:46 和 47。我也试着像这样写交集:

single_variant_ids & review_all_variant_ids 

但它给出了一个错误:

TypeError:合并“QuerySet”类在每种情况下必须涉及相同的值。

更新

我把第二个QuerySet的空列的名字改了:

review_all_variant_ids = VariantTag.objects.filter(variant_tag_type__name='Review') \                              
                .values_list('saved_variant_id', flat=True).annotate(id_count=Value(0, output_field=IntegerField()))

之后以下工作:

review_variant_ids = single_variant_ids & review_all_variant_ids

但是结果是错误的:

[22, 36, 46, 47]

所以,这里的交叉点是错误的,不像我需要的那样。当然,最简单的方法是将 QuerySets 都转换为 python sets 并计算它们的交集,但我想避免查询数据库直到最后一点。

【问题讨论】:

  • 您已经用 id_count 注释了第一个,这意味着它将是查询结果中的一列,该列在第二个查询中不存在,您可能只想将其注释为相交时保持列一致的值(0)
  • 太好了,快到了,您现在可以尝试在交叉路口进行初始尝试,也可以尝试以下过滤器:single_variant_ids .filter(saved_variant_id__in=review_all_variant_ids.values_list('saved_variant_id'))
  • 是的,这就是答案。如果您发布答案,我会接受它

标签: django django-orm python-2.x


【解决方案1】:

最初,您已使用 id_count 注释第一个查询,这意味着它将是查询结果中的一列,该列在第二个查询中不存在,您可能只想将其注释为值(0) 相交时保持列一致。

完成此操作后,您现在可以尝试在交叉路口进行初始尝试,也可以尝试使用此过滤器:

single_variant_ids.filter(saved_variant_id__in=review_all_variant_ids.values_list('saved_variant_id'))

一切顺利

【讨论】:

  • 很好的答案,我不知道当我在查询中注释时,会在数据库中创建一个新列。
  • @DanielDiaz 从技术上讲,该列只是添加到结果查询中,实际上并未作为永久新列添加到数据库中,但您可能已经理解了。
  • 谢谢你的解释,我真的没有,所以我很感激。
猜你喜欢
  • 2014-02-23
  • 2016-05-09
  • 2018-01-19
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
  • 2010-12-02
  • 1970-01-01
相关资源
最近更新 更多