2012-07-13 158 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