2011-10-19 127 views
9

我有機型數:Django的許多一對多

class Article(models.Model): 
    title = models.TextField(blank=True) 
    keywords = models.ManyToManyField(Keyword, null=True, blank=True) 

class Keyword(models.Model): 
    keyword = models.CharField(max_length=355, blank=True) 

我想的很多文章如何讓每個關鍵字的計數。實質上,我想要一個關鍵字列表,我可以讓每個關鍵字都給予相對權重。

我曾嘗試:

keyword_list=Article.objects.all().annotate(key_count=Count('keywords__keyword')) 

keyword_list[0].key_count  

似乎只是給我的不同關鍵字每篇文章都有多少?它以某種方式反向查找?

任何幫助將不勝感激。

UPDATE

所以我得到它的工作:

def keyword_list(request): 
    MAX_WEIGHT = 5 
    keywords = Keyword.objects.order_by('keyword') 
    for keyword in keywords: 
     keyword.count = Article.objects.filter(keywords=keyword).count() 
    min_count = max_count = keywords[0].count 
    for keyword in keywords: 
     if keyword.count < min_count: 
      min_count = keyword.count 
     if max_count > keyword.count: 
      max_count = keyword.count 
    range = float(max_count - min_count) 
    if range == 0.0: 
     range = 1.0 
    for keyword in keywords: 
     keyword.weight = (
      MAX_WEIGHT * (keyword.count - min_count)/range 
     ) 
    return { 'keywords': keywords } 

但查看結果在查詢中的一個可怕的數字。我試圖執行這裏給出的建議(謝謝),但這是目前似乎工作的唯一方法。但是,由於我現在有400多個查詢,所以我一定在做錯事!

UPDATE

嗚!最後得到它的工作:

def keyword_list(request): 
    MAX_WEIGHT = 5 
    keywords_with_article_counts = Keyword.objects.all().annotate(count=Count('keyword_set')) 
    # get keywords and count limit to top 20 by count 
    keywords = keywords_with_article_counts.values('keyword', 'count').order_by('-count')[:20] 
    min_count = max_count = keywords[0]['count'] 
    for keyword in keywords: 
     if keyword['count'] < min_count: 
      min_count = keyword['count'] 
     if max_count < keyword['count']: 
      max_count = keyword['count']    
    range = float(max_count - min_count) 
    if range == 0.0: 
     range = 1.0 
    for keyword in keywords: 
     keyword['weight'] = int(
      MAX_WEIGHT * (keyword['count'] - min_count)/range 
     ) 
    return { 'keywords': keywords} 

回答

16

既然你想的有每個關鍵字的文章數量,你必須做它的其他方式:

>>> Keyword.objects.all().annotate(article_count=models.Count('article'))[0].article_count 
2 
+0

爲什麼這下調了它似乎是正確的答案,或者我錯過了什麼? – solartic

+2

這確實是正確的答案,但可能會使用一點解釋。 – jathanism

+0

您可以將其簡化爲'Keyword.objects.all()。annotate(Count('article'))[0] .article__count' – guival

1

我不知道你會怎麼做有效,但如果你需要完成。

keywords = Keyword.objects.all() 
for keyword in keywords: 
    print 'Total Articles: %d' % (Article.objects.filter(keywords=keyword).count()) 
4

這是與從Vebjorn Ljosa答案,但有一點上下文,其中article_set是反向許多一對多關係對象的related_name

keywords_with_article_counts = Keyword.objects.all().annotate(article_count=Count('article_set')) 

說明你的結果,它會更容易返回.values()

keywords_with_article_counts.values('keyword', 'article_count') 

這將返回一個字典列表,將是這個樣子:

[{'article_count': 36, 'keyword': u'bacon'}, 
{'article_count': 4, 'keyword': u'unicorns'}, 
{'article_count': 8, 'keyword': u'python'}] 
+0

謝謝。這使得它更清晰一些,但我仍然無法將其融入我的觀點(請參閱我編輯的問題)。如果我返回一本字典,那麼這個觀點將會有很大的不同,不是嗎? –

+0

您可以將'keywords_with_article_counts' QuerySet原樣返回到您的視圖。我只是展示了'.values()'方法的使用,它允許您返回所需字段的字典而不是模型實例。這只是爲了說明'article_count'的結果,如果這很讓人困惑,那麼很抱歉。 – jathanism

+0

我現在有一個在我的shell中工作的修改版本,但由於我試圖將計數轉換爲一個權重並將關鍵字作爲對象提供,根據我上面的視圖,我有點迷路。關於我如何整合這個的任何提示? –