Django - Begrenzung der Abfrageergebnisse


Antworten:


304

Django-Abfragesätze sind faul. Das bedeutet, dass eine Abfrage nur dann in die Datenbank gelangt, wenn Sie speziell nach dem Ergebnis fragen.

Bis Sie das Ergebnis einer Abfrage drucken oder tatsächlich verwenden, können Sie ohne Datenbankzugriff weiter filtern.

Wie Sie unten sehen können, führt Ihr Code nur eine SQL-Abfrage aus, um nur die letzten 10 Elemente abzurufen.

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>]

Ich habe dies auf mongoDB versucht und es heißt, SELECT wird nicht unterstützt. Wie mache ich das auf mongoDB?
Winux

@winux Da dies Django-spezifisch ist, müssen Sie möglicherweise Django einrichten, um speziell mit Mongo / NoSQL-Datenbanken zu arbeiten. Dies ist meiner Erfahrung nach kein typisches Setup in Bezug auf das Standard-Django-ORM-Setup.
anonymer Feigling

38

Eigentlich denke ich, dass das LIMIT 10an die Datenbank ausgegeben wird, so dass das Schneiden nicht in Python, sondern in der Datenbank stattfinden würde.

Weitere Informationen finden Sie unter Einschränken von Abfragesätzen .


Beachten Sie, dass dies nicht für Abfragesätze funktioniert, die ebenfalls gefiltert werden müssen, da Sie nach dem Schneiden nicht filtern können.
Mike 'Pomax' Kamermans

2
Filtern Sie also zuerst, bevor Sie es in Scheiben schneiden. Danke Davor für den Link!
Vyachez

13

Es sieht so aus, als ob die Lösung in der Frage nicht mehr mit Django 1.7 funktioniert und einen Fehler auslöst: "Eine Abfrage kann nicht neu angeordnet werden, sobald ein Slice erstellt wurde."

Gemäß der Dokumentation https://docs.djangoproject.com/de/dev/topics/db/queries/#limiting-querysets wertet das Erzwingen des "step" -Parameters der Python-Slice-Syntax die Abfrage aus. Es funktioniert so:

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

Trotzdem frage ich mich, ob das Limit in SQL- oder Python-Slices ausgeführt wird und das gesamte Ergebnisarray zurückgegeben wird. Es ist nicht gut, große Listen in den Anwendungsspeicher abzurufen.


Auch diese Lösung funktioniert nicht mit Django> = 1.8 getestet.
Sonus21

3

Ja. Wenn Sie eine begrenzte Teilmenge von Objekten abrufen möchten, können Sie dies mit dem folgenden Code tun:

Beispiel:

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

Der Anfang 0 ist also optional

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

Der obige Code gibt die ersten 10 Instanzen zurück.


1

Als Ergänzung und Beobachtung zu den anderen nützlichen Antworten ist zu beachten, dass beim tatsächlichen [:10]Schneiden die ersten 10 Elemente der Liste zurückgegeben werden , nicht die letzten 10 ...

Um die letzten 10 zu erhalten, sollten Sie [-10:]stattdessen (siehe hier ) tun . Auf diese Weise können Sie vermeiden, die Elemente order_by('-id')mit -umzukehren.


1
Ich habe dies versucht und bekam "Negative Indizierung wird nicht unterstützt."
bparker

@DarkCygnus Product.objects.filter(~Q(price=0))[-5:]verursacht mir den gleichen Fehler: "Negative Indizierung wird nicht unterstützt."
Bersam

Dies funktioniert in Django auf einem Abfragesatz nicht: code.djangoproject.com/ticket/13089 Wenn Sie den Abfragesatz in eine Liste konvertieren, funktioniert er.
Valem
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.