Django管理器-覆盖默认的get“u query”集以设置默认值;分组方式;

Django管理器-覆盖默认的get“u query”集以设置默认值;分组方式;,django,django-queryset,Django,Django Queryset,我被遗留数据库卡住了。我想修改默认查询集,以便熟练地使用db,为此,我需要使用分组依据。我知道我可以做到这一点,从而获得我所追求的SQL: query = Variant.objects.all().query query.group_by = ['name'] return QuerySet(query=query, model=Variant) 这将导致我所追求的查询集。所以我建立了一个queryset管理器来帮助我。问题是它返回了正确的值,但当我对它进行计数时,它是错误的 class V

我被遗留数据库卡住了。我想修改默认查询集,以便熟练地使用db,为此,我需要使用
分组依据
。我知道我可以做到这一点,从而获得我所追求的SQL:

query = Variant.objects.all().query
query.group_by = ['name']
return QuerySet(query=query, model=Variant)
这将导致我所追求的查询集。所以我建立了一个queryset管理器来帮助我。问题是它返回了正确的值,但当我对它进行计数时,它是错误的

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?我以为_result_cache保存了这个值,所以我在方法中将它设置为None,但没有运气。知道这是怎么回事吗?

.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
这个问题实际上只有两种解决方案:

  • 按组名重写组,这样,它实际上返回一个过滤后的查询集,每个名称只包含一条记录,而不仅仅是按字段分组。难做
  • 当您需要分组查询集的“计数”时,只需使用
    len()
    ,如中所示

    len(Variant.objects.filter(project__name__icontains="zam").group_by_name())
    
    或者,在模板中:

    {{ grouped_variants|length }}
    

  • 请注意,这意味着必须对整个查询进行计算(而不是通常更快的
    count()
    query),但我认为这里的大部分开销都会在聚合中,不管您希望如何。因此,您最好执行真正的查询,然后对其调用
    len
    。这正是我遵循的路径。很高兴知道我在正确的轨道上。我最终还是加入了len(团队),因为这是最有意义的。
    {{ grouped_variants|length }}