2010-01-19 2 views
17

prendendo l'esempio da: http://docs.djangoproject.com/en/dev/topics/db/aggregation/#filter-and-excludefiltraggio solo su Annotazioni a Django

Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book')) 

Esiste un modo per avere il filtro si applicano solo per l'annotazione, quindi sarebbe tornare tutti gli editori, con alcuni che hanno un NUM_BOOKS = 0 ?

+0

Quindi, vuoi un elenco di tutti gli editori, ciascuno annotato con il loro numero di libri di alto livello? –

+0

Sì, e tale elenco dovrebbe includere editori che non hanno libri o solo libri con valutazioni basse. –

risposta

18

È possibile utilizzare la variabile di annotazione nel filtro.

publishers=Publisher.objects.annotate(num_books=Count('book')).filter(num_books__gte=2) 
+0

No, questo non è quello che voglio. –

+0

Uhhh ... cosa vuoi ... – czarchaic

+0

Voglio dire, voglio che tutti gli editori vengano restituiti, e ogni editore dovrebbe essere annotato con il numero di libri con valutazioni elevate. Pertanto, nell'elenco degli editori dovrebbero figurare editori con meno di 2 libri con valutazioni elevate e editori con solo libri con basso punteggio e editori che non hanno affatto libri. Fammi sapere se posso chiarirlo meglio. –

0

Si può provare qualcosa di simile:

Book.objects.values('publisher').annotate(num_books=Count('id')) 
+1

Quello sarebbe il conteggio di tutti i libri, non solo quelli con una valutazione superiore a 3. –

10

Hm, io penso che si debba usare un extra clause:

Publisher.objects.extra(select={ 
    'num_books': 'SELECT COUNT(*) ' + \ 
       'FROM <your_app>_book ' + \ 
       'WHERE <your_app>_book.publisher_id = ' + \ 
         '<your_app>_publisher.id AND ' + \ 
         'rating > 3.0' 
}) 
+0

Questa è la migliore risposta che ho visto finora. Sarebbe bello se non avessi dovuto usare sql raw però. –

+0

È vero! Questo non dovrebbe causare problemi di compatibilità, però. Ma per favore fatemi sapere, se si scopre un modo per farlo senza raw sql! – Maccesch

+1

Probabilmente si può usare il metodo QuerySet._as_sql (connessione), per generare query non elaborate da Django stesso. Little hack ma è ancora meglio che scriverlo da solo. – farincz

5
from django.db import models 

Publisher.objects.annotate(
    num_books=models.Sum(
     models.Case(
      models.When(
       book__rating__gt=3.0, 
       then=1, 
      ), 
      default=0, 
      output_field=models.IntegerField(), 
     ) 
    ) 
).filter(
    num_books=0, 
) 
+0

Sembra vicino, ma non filtrare per "num_books = 0" alla fine. Tutti i publisher dovrebbero essere restituiti. –

0

Ho appena di fronte a questo tipo di problema. E se la mia interpreazione per il problema e la soluzione prevista è corretta, questa è la mia soluzione di lavoro:
Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0) Solo posizione di annotazione del filtro di scambio &. Questo è fatto in Django versione 1.9

+0

Questo è lo stesso codice esatto che ho nella mia domanda (nemmeno scambiato). Il problema che stavo avendo è che non mostra i publisher che hanno 0 libri. Non voglio affatto filtrare gli editori, voglio solo filtrare il conteggio. –

+0

Siamo spiacenti, ho dimenticato di modificare il codice di esempio. Ma questo è quello che stavo implementando quando voglio usare il filtro e annotare nel mio queryset. E sfortunatamente, non ho letto chiaramente la tua domanda su 0 editore di libri. – pupil