Django指望多对多

Dar*_*ech 11 django django-orm

我有模特:

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)
Run Code Online (Sandbox Code Playgroud)

我想知道每个关键字有多少篇文章.从本质上讲,我希望有一个关键字列表,我可以在每个关键字中计算它们的相对权重.

我试过了:

keyword_list=Article.objects.all().annotate(key_count=Count('keywords__keyword'))
Run Code Online (Sandbox Code Playgroud)

keyword_list[0].key_count    
Run Code Online (Sandbox Code Playgroud)

只是似乎给了我每篇文章不同关键词的数量?它是以某种方式反向查找?

任何帮助将非常感激.

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 }
Run Code Online (Sandbox Code Playgroud)

但是该视图导致了大量的查询.我已经尝试过实施这里给出的建议(谢谢),但这是目前唯一可行的方法.但是,我必须做错事,因为我现在有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}
Run Code Online (Sandbox Code Playgroud)

Veb*_*osa 18

由于您需要包含每个关键字的文章数量,因此您必须采用另一种方式:

>>> Keyword.objects.all().annotate(article_count=models.Count('article'))[0].article_count
2
Run Code Online (Sandbox Code Playgroud)

  • 这确实是正确的答案,但可能会使用一些解释. (2认同)

jat*_*ism 8

这是与从答案Vebjorn Ljosa,但有一点背景,这里article_setrelated_name反向许多一对多关系的对象。

keywords_with_article_counts = Keyword.objects.all().annotate(article_count=Count('article_set'))
Run Code Online (Sandbox Code Playgroud)

为了说明您的结果,返回以下内容会更容易.values()

keywords_with_article_counts.values('keyword', 'article_count')
Run Code Online (Sandbox Code Playgroud)

这将返回一个看起来像这样的字典列表:

[{'article_count': 36, 'keyword': u'bacon'}, 
 {'article_count': 4, 'keyword': u'unicorns'}, 
 {'article_count': 8, 'keyword': u'python'}]
Run Code Online (Sandbox Code Playgroud)