Django - ograniczenie wyników zapytań


Odpowiedzi:


304

Zestawy zapytań Django są leniwe. Oznacza to, że zapytanie trafi do bazy danych tylko wtedy, gdy poprosisz o wynik.

Więc dopóki nie wydrukujesz lub nie użyjesz wyniku zapytania, możesz filtrować dalej bez dostępu do bazy danych.

Jak widać poniżej, kod wykonuje tylko jedno zapytanie SQL, aby pobrać tylko 10 ostatnich elementów.

In [19]: import logging                                 
In [20]: l = logging.getLogger('django.db.backends')    
In [21]: l.setLevel(logging.DEBUG)                      
In [22]: l.addHandler(logging.StreamHandler())      
In [23]: User.objects.all().order_by('-id')[:10]          
(0.000) SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" ORDER BY "auth_user"."id" DESC LIMIT 10; args=()
Out[23]: [<User: hamdi>]

Próbowałem tego na mongoDB i napisano, że SELECT nie jest obsługiwane. Jak to zrobić na mongoDB?
winux

@winux Ponieważ jest to specyficzne dla Django, wygląda na to, że możesz potrzebować skonfigurować Django do pracy z bazami danych typu Mongo / NoSQL. Z mojego doświadczenia nie jest to typowa konfiguracja w odniesieniu do standardowej konfiguracji Django ORM.
anonimowy tchórz

38

Właściwie myślę, LIMIT 10że zostaną wydane do bazy danych, więc krojenie nie nastąpi w Pythonie, ale w bazie danych.

Aby uzyskać więcej informacji, zobacz zestawy zapytań ograniczających .


Pamiętaj, że to nie zadziała w przypadku zestawów zapytań, które również wymagają filtrowania, ponieważ nie można filtrować po krojeniu.
Mike 'Pomax' Kamermans

2
Więc przefiltruj najpierw niż pokrój go. Dzięki Davor za link!
Vyachez

13

Wygląda na to, że rozwiązanie w pytaniu nie działa już w Django 1.7 i pojawia się błąd: „Nie można zmienić kolejności zapytania po pobraniu plastra”

Zgodnie z dokumentacją https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets wymuszając parametr „step” składni plastra Python ocenia zapytanie. Działa w ten sposób:

Model.objects.all().order_by('-id')[:10:1]

Nadal zastanawiam się, czy limit jest wykonywany w SQL, czy w Pythonie wycina całą tablicę wyników. Nie ma potrzeby pobierania ogromnych list do pamięci aplikacji.


Nawet to rozwiązanie nie działa z testowanym django> = 1.8.
sonus21

3

Tak. Jeśli chcesz pobrać ograniczony podzbiór obiektów, możesz użyć poniższego kodu:

Przykład:

obj=emp.objects.all()[0:10]

Początkowe 0 jest opcjonalne, więc

obj=emp.objects.all()[:10]

Powyższy kod zwraca pierwsze 10 wystąpień.


1

Jako uzupełnienie i spostrzeżenie do innych użytecznych odpowiedzi, warto zauważyć, że faktyczne wykonanie [:10]wycinania zwróci pierwsze 10 elementów listy , a nie ostatnie 10 ...

Aby zdobyć ostatnie 10, powinieneś zrobić [-10:]zamiast tego (patrz tutaj ). Pomoże to uniknąć korzystania order_by('-id')z przy -odwracaniu elementów.


1
Próbowałem tego i otrzymałem „Negatywne indeksowanie nie jest obsługiwane”.
bparker

@DarkCygnus Product.objects.filter(~Q(price=0))[-5:]powoduje ten sam błąd: „Indeksowanie ujemne nie jest obsługiwane”.
bersam

To nie działa w django na zestawie zapytań: code.djangoproject.com/ticket/13089 Jeśli przekonwertujesz zestaw zapytań na listę, zadziała.
valem
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.