2011-10-19 12 views
9

mam modele:Django liczyć na wiele-do-wielu

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) 

Chcę uzyskać rachubę, ile artykułów mieć każdego słowa kluczowego. W gruncie rzeczy chcę mieć listę słów kluczowych, w których każdy może policzyć, aby uzyskać względną wagę.

Próbowałem:

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

ale

keyword_list[0].key_count  

prostu wydaje mi dać numer różnych słów kluczowych każdy artykuł ma? Czy jest to w jakiś sposób odwrotne wyszukiwanie?

Każda pomoc będzie mile widziana.

UPDATE

Więc mam to działa:

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 } 

ale widok wyników w ohydnym liczby zapytań. Próbowałem realizować podane tu sugestie (dziękuję), ale jest to jedyny metid, który wydaje się działać w tej chwili. Jednak muszę zrobić coś złego, ponieważ mam ponad 400 zapytań!

UPDATE

wooh! W końcu dostał pracę:

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} 

Odpowiedz

16

Ponieważ chcesz liczbę artykułów, które każdego słowa kluczowego, trzeba zrobić to w inny sposób:

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

Dlaczego to w dół głosowało, że wygląda na poprawną odpowiedź, czy coś mi brakuje? – solartic

+2

Jest to rzeczywiście poprawna odpowiedź, ale prawdopodobnie użyłby trochę wyjaśnienia. – jathanism

+0

Możesz uprościć go do 'Keyword.objects.all(). Adnotate (Count ('article')) [0] .article__count' – guival

1

nie wiem w jaki sposób to zrobić sprawnie, ale jeśli musisz to zrobić.

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

ten jest taki sam jak na odpowiedź z Vebjorn Ljosa, ale z niewielkim kontekście, gdzie article_set jest related_name odwrotnej wiele-do-wielu obiektów związku.

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

Aby zilustrować swoje wyniki, byłoby łatwiejsze do zwrotu .values():

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

Które zwraca listę słowników, które wyglądają mniej więcej tak:

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

Dzięki. Czyni to trochę jaśniej, chociaż wciąż mam problem z integracją tego z moim zdaniem (zobacz moje zredagowane pytanie). Jeśli zwrócę słownik, to ten widok będzie musiał znacznie się różnić, nie? –

+0

Możesz powrócić do widoku z zestawu kwerend 'keywords_with_article_counts' QuerySet. Właśnie pokazałem użycie metody '.values ​​()', która pozwala na zwrócenie słownika żądanych pól zamiast instancji modelu. To było po prostu zilustrowanie wyników 'article_count', przepraszam, jeśli to było mylące. – jathanism

+0

Mam teraz zmodyfikowaną wersję tego działa w mojej powłoce, ale jak próbuję przekształcić licznik na wagę i dostarczyć słowa kluczowe jako obiekty, jak na mój widok powyżej, jestem mało zagubiony. Wszelkie wskazówki, jak to zintegrować? –