0

我被遗留数据库困住了。我想修改默认查询集以便熟练使用数据库,为此我需要使用GROUP BY. 我知道我可以做到这一点,这让我得到了我所追求的 SQL:

query = Variant.objects.all().query
query.group_by = ['name']
return QuerySet(query=query, model=Variant)

这将产生我所追求的查询集。所以我建立了一个查询集管理器来帮助我。问题是它返回了正确的值,但是当我计算它时它是错误的。

class VariantQuerySet(QuerySet):
    def group_by_name(self):
        self.query.group_by = ['name']
        return self.filter()

class VariantManager(models.Manager):

    def get_query_set(self):
        return VariantQuerySet(self.model, using=self._db)

但是当我开始玩它时..

>>> Variant.objects.filter(project__name__icontains="zam")
[<Variant: RevA>, <Variant: RevA>, <Variant: RevA>, <Variant: revB>, <Variant: RevC_Fiendish>, <Variant: RevA>, <Variant: RevA_tapeout>]
>>> Variant.objects.filter(project__name__icontains="zam").count()
7
>>> Variant.objects.filter(project__name__icontains="zam").group_by_name()
[<Variant: RevA>, <Variant: revB>, <Variant: RevC_Fiendish>, <Variant: RevA_tapeout>]

到目前为止,一切都很好。7 个未分组的项目,4 个分组。

>>> Variant.objects.filter(project__name__icontains="zam").group_by_name().count()
7

那么为什么我的计数仍然停留在 7 - 它应该是 4?我认为 _result_cache 持有该值,所以我在方法中将其设置为 None 但没有运气。任何想法为什么这是错误的?

4

1 回答 1

1

.count()实际上创建了一个新查询,将字段删除并替换为COUNT(*). 实际上不可能按字段分组在普通 SQL 中对分组表进行计数。基本上,您最初的查询在 SQL 中如下所示:

SELECT myapp_variant.id, myapp_variant.name, myapp_variant.etc, ...
FROM myapp_variant inner join myapp_project on myapp_variant.project_id = myapp_project.id
WHERE myapp_project.name='zam'
GROUP BY myapp_variant.name

计数查询如下所示:

SELECT COUNT(*)
FROM myapp_variant inner join myapp_project on myapp_variant.project_id = myapp_project.id
WHERE myapp_project.name='zam'

请注意,它不能再分组。如果是这样,您最终会得到以下结果集:

COUNT
-----
    4 
    1
    1
    1

(在这种情况下,4 是 RevA 记录的数量,然后是其他每个记录的 1)

因为当您在聚合查询中分组时,您是在告诉 SQL 为每个分组列中的每个唯一值创建一行。4 种不同的变体名称,因此 4 条记录!这根本不是你想要的

您可以通过输出 Django 生成的查询来确认这是否是问题所在:

>>> print Variant.objects.filter(project__name__icontains="zam").group_by_name().query

>>> print Variant.objects.filter(project__name__icontains="zam").group_by_name().count().query

这个问题实际上只有两种解决方案:

  1. 重写 group_by_name 以便它不只是按字段分组,它实际上返回一个过滤的查询集,每个名称只有一条记录。更难做
  2. 当您需要分组查询集的“计数”时,只需使用len(),如

    len(Variant.objects.filter(project__name__icontains="zam").group_by_name())
    

    或者,在模板中:

    {{ grouped_variants|length }}
    
于 2012-07-13T15:46:03.977 回答