Chcę wziąć ostatnie 10 instancji modelu i mieć ten kod:
Model.objects.all().order_by('-id')[:10]
Czy to prawda, że najpierw zbieraj wszystkie wystąpienia, a następnie weź tylko 10 ostatnich? Czy istnieje bardziej skuteczna metoda?
Chcę wziąć ostatnie 10 instancji modelu i mieć ten kod:
Model.objects.all().order_by('-id')[:10]
Czy to prawda, że najpierw zbieraj wszystkie wystąpienia, a następnie weź tylko 10 ostatnich? Czy istnieje bardziej skuteczna metoda?
Odpowiedzi:
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>]
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 .
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.
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ń.
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.
Product.objects.filter(~Q(price=0))[-5:]
powoduje ten sam błąd: „Indeksowanie ujemne nie jest obsługiwane”.