2011-10-19 17 views
9

tengo los modelos:Django contar con muchos-a-muchos

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) 

quiero obtener un recuento de cómo muchos artículos tienen cada palabra clave. En esencia, quiero tener una lista de palabras clave donde pueda obtener el recuento de cada uno para darle una ponderación relativa.

que he intentado:

keyword_list=Article.objects.all().annotate(key_count=Count('keywords__keyword')) 

pero

keyword_list[0].key_count  

sólo parece que me diera el número de diferentes palabras clave cada artículo tiene? ¿Es de alguna manera una búsqueda inversa?

Cualquier ayuda sería muy apreciada.

ACTUALIZACIÓN

Así que tengo trabajo:

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 } 

pero la vista los resultados en una serie espantosa de consultas. He tratado de implementar las sugerencias dadas aquí (gracias) pero este es el único metid que parece funcionar en este momento. Sin embargo, debo estar haciendo algo mal ya que ahora tengo más de 400 consultas.

ACTUALIZACIÓN

Wooh! Finalmente lo consiguió trabajo:

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} 

Respuesta

16

Desde desea que el número de artículos que tienen cada palabra clave, usted tiene que hacerlo a la inversa:

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

¿Por qué es esta votación negativa parece ser la respuesta correcta, ¿o me falta algo? – solartic

+2

Esta es de hecho la respuesta correcta, pero probablemente podría usar una pequeña explicación. – jathanism

+0

Puede simplificarlo a 'Keyword.objects.all(). Annotate (Count ('artículo')) [0] .article__count' – guival

1

no sé cómo lo haría de manera eficiente, pero si necesita hacerlo.

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

Esta es la misma que la respuesta de Vebjorn Ljosa, pero con un poco de contexto, donde article_set es el related_name del objeto relación muchos-a-muchos inversa.

keywords_with_article_counts = Keyword.objects.all().annotate(article_count=Count('article_set')) 

Para ilustrar los resultados, sería más fácil para devolver el .values():

keywords_with_article_counts.values('keyword', 'article_count') 

Lo cual devolverá una lista de diccionarios que sería algo como esto:

[{'article_count': 36, 'keyword': u'bacon'}, 
{'article_count': 4, 'keyword': u'unicorns'}, 
{'article_count': 8, 'keyword': u'python'}] 
+0

Gracias. Eso lo hace un poco más claro, aunque todavía tengo problemas para integrar esto en mi opinión (ver mi pregunta editada). Si devuelvo un diccionario, esta vista tendrá que ser significativamente diferente, ¿no? –

+0

Puede devolver el QuerySet 'keywords_with_article_counts' tal como está a su vista. Solo estaba mostrando el uso del método '.values ​​()', que le permite devolver un diccionario de los campos deseados en lugar de las instancias del modelo. Eso fue solo para ilustrar los resultados de 'article_count', lo siento si eso fue confuso. – jathanism

+0

Ahora tengo una versión modificada de este trabajo en mi caparazón, pero como estoy tratando de transformar el recuento en un peso y entregar palabras clave como objetos, según mi opinión anterior, estoy un poco perdido. ¿Algún consejo sobre cómo puedo integrar esto? –