【问题标题】:Django count on many-to-manyDjango 依靠多对多
【发布时间】:2011-12-11 03:55:38
【问题描述】:

我有模型:

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    

似乎只是给了我每篇文章的不同关键字的数量?不知何故是反向查找?

任何帮助将不胜感激。

更新

所以我得到了它的工作:

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 多个查询!

更新

哇!终于搞定了:

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}

【问题讨论】:

    标签: django django-orm


    【解决方案1】:

    由于您想要每个关键字的文章数量,因此您必须以另一种方式进行:

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

    【讨论】:

    • 这确实是正确答案,但可能需要一点解释。
    • 可以简化为Keyword.objects.all().annotate(Count('article'))[0].article__count
    【解决方案2】:

    这与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'}]
    

    【讨论】:

    • 谢谢。这使它更清晰一些,尽管我仍然无法将其整合到我的视图中(请参阅我编辑的问题)。如果我返回一个字典,那么这个视图肯定会有很大的不同,不是吗?
    • 您可以将keywords_with_article_counts QuerySet 原样返回到您的视图中。我只是展示了.values() 方法的使用,它允许您返回所需字段的字典而不是模型实例。这只是为了说明article_count 的结果,如果造成混淆,请见谅。
    • 我现在在我的 shell 中有一个修改版本,但是当我试图将计数转换为权重并将关键字作为对象传递时,根据我上面的观点,我有点迷失。关于如何整合它的任何提示?
    【解决方案3】:

    我不知道您将如何有效地做到这一点,但如果您需要完成它。

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

    【讨论】:

      猜你喜欢
      • 2016-09-11
      • 1970-01-01
      • 2021-02-12
      • 2020-05-07
      • 2017-05-15
      • 1970-01-01
      • 2019-09-08
      • 2013-03-28
      • 2019-01-14
      相关资源
      最近更新 更多