2014-04-22 12 views
9

Ho una situazione simile a questa (il codice effettivo è associato a un modello e omesso per brevità).Il prefetch_jango di Django è valido solo per il conteggio

threads = Thread.objects.all() 
for thread in threads: 
    print(thread.comments.count()) 
    print(thread.upvotes.count()) 

sono riuscito a ridurre notevolmente il numero totale di query utilizzando il metodo impressionante prefetch_related di Django.

threads = Thread.objects.prefetch_related('comments').prefetch_related('upvotes') 

Tuttavia mi chiedo se questa situazione potrebbe essere ulteriormente ottimizzata. Da quanto ho capito, prefetch_related recupera tutti i dati associati ai modelli correlati. Visto che mi interessa solo la quantità di modelli correlati e non i modelli stessi, sembra che questa query possa essere ulteriormente ottimizzata in modo che non recuperi un mucchio di dati non necessari. C'è un modo per farlo in Django senza scendere a SQL raw?

risposta

11

Hai ragione, è uno spreco recuperare tutti i dati dal database se tutto ciò che vuoi è ottenere il conteggio. Suggerisco di annotazione:

threads = (Thread.objects.annotate(Count('comments', distinct=True)) 
         .annotate(Count('upvotes', distinct=True))) 
for thread in threads: 
    print(thread.comments__count) 
    print(thread.upvotes__count) 

Vedere la annotation documentation per ulteriori informazioni.

+0

Impressionante questo fa esattamente quello che volevo, grazie! Anche cercando tra i documenti di Django sembra che 1.7 sarà in grado di ottenere qualcosa di simile a quello che ho descritto usando la nuova classe Prefetch e un set di query personalizzato che rimuove i campi inutilizzati. Tuttavia, la tua soluzione funziona con versioni non sanguinanti di Django. – rectangletangle

+3

@rectangletangle: se tutto quello che ti interessa è il conteggio, l'annotazione dovrebbe funzionare meglio di 'prefetch_related'. Anche se differisci tutto tranne l'id, non c'è motivo di recuperare un intero per ogni commento quando puoi recuperare un intero (il conteggio) per ogni thread. –

+0

Questo è un buon punto. Tra questo e la compatibilità, penso che tu abbia la soluzione migliore per questo caso d'uso. – rectangletangle

Problemi correlati