title: Django count on many-to-many
body: <p>I have the models:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>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.</p>
  
  <p>I have tried: </p>
  
  <pre><code>keyword_list=Article.objects.all().annotate(key_count=Count('keywords__keyword'))
  </code></pre>
  
  <p>but </p>
  
  <pre><code>keyword_list[0].key_count    
  </code></pre>
  
  <p>just seems to give me the number of <em>different</em> keywords each article has? Is it somehow a reverse lookup?</p>
  
  <p>Any help would be much appreciated.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>So I got it working:</p>
  
  <pre><code>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 &lt; min_count:
              min_count = keyword.count
          if max_count &gt; 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 }
  </code></pre>
  
  <p>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!</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Wooh! Finally got it working:</p>
  
  <pre><code>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'] &lt; min_count:
              min_count = keyword['count']
          if max_count &lt; 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}
  </code></pre>