2014-07-11 24 views
14

Czy istnieje sposób, aby powiedzieć prefetch_related, aby pobrać tylko ograniczony zestaw powiązanych obiektów? Powiedzmy, że pobieram listę użytkowników i wiem, że chcę pobrać ich ostatnie komentarze. Zamiast pobierać komentarze dla każdego użytkownika w pętli, używam prefetch_related do wstępnego pobierania ich w momencie pobierania użytkowników. Rozumiem, że spowoduje to pobranie wszystkich komentarzy zgłoszonych przez dowolnego użytkownika w wyniku pierwotnego zapytania, ale chcę pokazać tylko 5 ostatnich dla każdego użytkownika.Django Prefetch_related z limitem

Jak to wpływa na wydajność, jeśli lista komentarzy jest naprawdę duża? Czy istnieje sposób na pobranie tylko 5 komentarzy dla każdego użytkownika w pojedynczym (lub 2) zapytaniu? Nie musi to być ta sama kwerenda, co oryginalna dla pobierania użytkowników, ale byłoby to miłe.

I zasadniczo chcą włączyć tę

users = User.objects.all() 
    for user in users: 
     user.comments.all()[:10] 

na coś takiego

User.objects.all().prefetch_related('comments', limit=10) 

więc jeśli użytkownik ma 100s lub 10000S uwag, nie wszystkie są ładowane do pamięci. Jak zrobiłbyś coś takiego w surowym SQL?

+0

Nie sądzę, że używanie pobierania wstępnego to dobry sposób na zrobienie tego. W rzeczywistości prefetch_related wykonuje oddzielne wyszukiwanie dla każdej relacji i łączy się w Pythonie. Oznacza to, że wstępnie wczytasz komentarze w pythonie, a dołączenie zostanie wykonane z tej wstępnie załadowanej listy komentarzy. W twoim przypadku, aby mieć pewność, że masz 10 ostatnich komentarzy każdego użytkownika, musisz wstępnie załadować wszystkie z nich. – trnsnt

+0

Mogę żyć z jednym zapytaniem dla każdej relacji, ale jedno zapytanie na obiekt jest prawdziwym zabójcą. –

+0

Zgadzam się, jedno zapytanie na obiekt jest koszmarem. Ale dlaczego nie po prostu robić: 'users = User.objects.all(). Prefetch_related ('comments')' W takim przypadku będziesz wykonywać tylko 2 zapytania – trnsnt

Odpowiedz

4

Jedynym sposobem ograniczenia liczby uprzednio pobranych obiektów pokrewnych wydaje się być użycie Prefetch() i filtrowanie na plikach. Korzystanie sliceing

User.objects.all().prefetch_related(
    Prefetch('msg_sent', queryset=UserMsg.objects.order_by('-created')[:10])) 

zwraca błąd

AssertionError: Cannot filter a query once a slice has been taken. 

Jedynym sposobem na ograniczenie liczby powiązanych obiektów wydaje się być za pomocą filtra na wartości, na przykład

from datetime import datetime, timedelta 
timelimit = datetime.now() - timedelta(days=365) 

User.objects.all().prefetch_related(
    Prefetch('msg_sent', queryset=UserMsg.objects.filter(created__gte=timelimit))) 

Mimo, że nie robi Zwrócenie ustalonej liczby może być użyteczne w niektórych sytuacjach i zmniejszy liczbę uprzednio pobranych obiektów.

+7

Oto bilet o obiekcie 'Prefetch' nie akceptujący zestawów zapytań z plasterkami: https: //code.djangoproject. com/ticket/26780 –

Powiązane problemy