2014-04-22 13 views
9

Mam sytuację coś takiego (rzeczywisty kod jest związany w szablonie i pominięty dla zwięzłości).Django's prefetch_related dla liczyć tylko

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

udało mi się znacznie zmniejszyć całkowitą liczbę zapytań z wykorzystaniem metody niesamowite prefetch_related Django.

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

Zastanawiam się jednak, czy ta sytuacja może być dalej zoptymalizowana. Z tego co wiem, prefetch_related pobiera wszystkie dane powiązane z powiązanymi modelami. Widząc, że zależy mi tylko na ilości powiązanych modeli, a nie na samych modelach, wydaje się, że to zapytanie może zostać zoptymalizowane, tak aby nie pobierać mnóstwa niepotrzebnych danych. Czy jest jakiś sposób na zrobienie tego w Django bez sprowadzania się do surowego SQL?

Odpowiedz

11

Masz rację, marnowanie czasu na pobieranie wszystkich danych z bazy danych, jeśli wszystko, co chcesz zrobić, to uzyskać liczbę. Proponuję adnotacji:

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) 

Patrz annotation documentation aby uzyskać więcej informacji.

+0

Awesome to robi dokładnie to, co chciałem, dzięki! Przeszukując także dokumenty Django, wygląda na to, że 1.7 będzie w stanie osiągnąć coś podobnego do tego, co opisałem przy użyciu nowej klasy Prefetch i niestandardowego zestawu zapytań, który odfiltruje nieużywane pola. Jednak twoje rozwiązanie działa z nieinwazyjnymi wersjami Django. – rectangletangle

+3

@rectangletangle: Jeśli wszystko, na czym zależy, to liczba, adnotacja powinna nadal działać lepiej niż "prefetch_related". Nawet jeśli odrzucisz wszystko oprócz identyfikatora, nie ma powodu, aby pobierać jedną liczbę całkowitą dla każdego komentarza, gdy możesz pobrać jedną liczbę całkowitą (liczbę) dla każdego wątku. –

+0

To dobra uwaga. Pomiędzy tym a kompatybilnością, myślę, że masz najlepsze rozwiązanie dla tego przypadku użycia. – rectangletangle