2012-07-13 87 views
0

我被遗留下来的数据库。我想修改默认查询集以便熟练地使用数据库,为此我需要使用GROUP BY。我知道我可以做到这一点,这让我后来的SQL:Django Manager - 覆盖默认的get_query_set设置默认的“GROUP BY”

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,但没有运气。任何想法,为什么这是错的?

回答

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 }} 
    
+0

注意这意味着必须对整个查询进行评估(而不是通常更快的'count()'查询),但我认为这里的大部分开销将在您希望的聚合中进行,无论如何。所以你不妨做真正的查询,只需调用'len'即可。 – 2012-07-13 15:47:55

+0

这正是我所遵循的道路。很高兴知道我在正确的轨道上。我确实最终得到了len(组),因为它是最有意义的。 – rh0dium 2012-07-16 20:43:33