I have the models:
我的模型:
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)
I want to get a count of how many articles have each keyword. In essence I want to have a list of keywords where I can get each ones count to give it a relative weighting.
我想知道每个关键词有多少篇文章。本质上,我想要有一个关键字的列表,在这里我可以让每个关键字都有一个相对的权重。
I have tried:
我有尝试:
keyword_list=Article.objects.all().annotate(key_count=Count('keywords__keyword'))
but
但
keyword_list[0].key_count
just seems to give me the number of different keywords each article has? Is it somehow a reverse lookup?
似乎每一篇文章都有不同的关键词。是反向查找吗?
Any help would be much appreciated.
如有任何帮助,我们将不胜感激。
UPDATE
更新
So I got it working:
所以我让它起作用:
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 }
but the view results in a hideous number of queries. I have tried implementing the suggestions given here (thanks) but this is the only methid which seems to work at the moment. However, I must be doing something wrong as I now have 400+ queries!
但是视图会产生大量的查询。我已经尝试执行这里给出的建议(谢谢),但这是目前唯一可行的方法。但是,我一定做错了什么,因为我现在有400多个查询!
UPDATE
更新
Wooh! Finally got it working:
Wooh !终于它工作:
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}
3 个解决方案
#1
17
Since you want the number of articles that have each keyword, you have to do it the other way:
既然你想要每个关键词都包含的文章的数量,你必须用另一种方式:
>>> Keyword.objects.all().annotate(article_count=models.Count('article'))[0].article_count
2
#2
4
This is the same as the answer from Vebjorn Ljosa, but with a little context, where article_set
is the related_name
of the reverse many-to-many relationship object.
这与Vebjorn Ljosa的答案相同,但是有一个小的上下文,其中article_set是反向多对多关系对象的related_name。
keywords_with_article_counts = Keyword.objects.all().annotate(article_count=Count('article_set'))
To illustrate your results, it would be easier to return the .values()
:
为了说明您的结果,可以更容易地返回.values():
keywords_with_article_counts.values('keyword', 'article_count')
Which would return a list of dictionaries that would look something like this:
它会返回一个字典列表看起来像这样:
[{'article_count': 36, 'keyword': u'bacon'},
{'article_count': 4, 'keyword': u'unicorns'},
{'article_count': 8, 'keyword': u'python'}]
#3
1
i don't know how you would do it efficiently but if you need to get it done.
我不知道你会怎么做,但如果你需要做的话。
keywords = Keyword.objects.all()
for keyword in keywords:
print 'Total Articles: %d' % (Article.objects.filter(keywords=keyword).count())
#1
17
Since you want the number of articles that have each keyword, you have to do it the other way:
既然你想要每个关键词都包含的文章的数量,你必须用另一种方式:
>>> Keyword.objects.all().annotate(article_count=models.Count('article'))[0].article_count
2
#2
4
This is the same as the answer from Vebjorn Ljosa, but with a little context, where article_set
is the related_name
of the reverse many-to-many relationship object.
这与Vebjorn Ljosa的答案相同,但是有一个小的上下文,其中article_set是反向多对多关系对象的related_name。
keywords_with_article_counts = Keyword.objects.all().annotate(article_count=Count('article_set'))
To illustrate your results, it would be easier to return the .values()
:
为了说明您的结果,可以更容易地返回.values():
keywords_with_article_counts.values('keyword', 'article_count')
Which would return a list of dictionaries that would look something like this:
它会返回一个字典列表看起来像这样:
[{'article_count': 36, 'keyword': u'bacon'},
{'article_count': 4, 'keyword': u'unicorns'},
{'article_count': 8, 'keyword': u'python'}]
#3
1
i don't know how you would do it efficiently but if you need to get it done.
我不知道你会怎么做,但如果你需要做的话。
keywords = Keyword.objects.all()
for keyword in keywords:
print 'Total Articles: %d' % (Article.objects.filter(keywords=keyword).count())