2011-10-19 125 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中工作的修改版本,但由于我试图将计数转换为一个权重并将关键字作为对象提供,根据我上面的视图,我有点迷路。关于我如何整合这个的任何提示? –