In Django nach leerem Abfrageset suchen

182

Was ist die empfohlene Redewendung, um zu überprüfen, ob eine Abfrage Ergebnisse zurückgibt?
Beispiel:

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc')
# If any results
    # Do this with the results without querying again.
# Else, do something else...

Ich nehme an, es gibt verschiedene Möglichkeiten, dies zu überprüfen, aber ich würde gerne wissen, wie ein erfahrener Django-Benutzer dies tun würde. Die meisten Beispiele in den Dokumenten ignorieren einfach den Fall, in dem nichts gefunden wurde ...

Niklas
quelle

Antworten:

204
if not orgs:
    # Do this...
else:
    # Do that...
Adam
quelle
5
Dies scheint auch in der Dokumentation bevorzugt zu sein, zum Beispiel: docs.djangoproject.com/de/1.8/topics/http/shortcuts/#id7
Wtower
1
@Wtower Der Code, auf den Sie sich beziehen, muss vertraglich 404 auslösen, wenn der Filterausdruck keine Datensätze trifft, oder ein listErgebnis erzeugen, wenn Datensätze vorhanden sind. Der Code dort wird nur einmal in die Datenbank gelangen. Wenn sie verwendet haben exist()oder count()zuerst prüfen, ob Datensätze zurückgegeben werden, greifen sie zweimal auf die Datenbank zu (einmal zum Überprüfen, einmal zum Abrufen der Datensätze). Dies ist eine spezielle Situation. Es bedeutet nicht, dass im allgemeinen Fall die bevorzugte Methode, um zu wissen, ob eine Abfrage Datensätze zurückgibt, die Verwendung von doif queryset:...
Louis
1
@ Louis Der Code, auf den ich mich beziehe, ist nur ein Beispiel dafür, dass er eine Zeile enthält, um if not my_objects:zu demonstrieren, dass dies in den Dokumenten so ist. Alles andere ist völlig irrelevant, daher verstehe ich Ihren Standpunkt nicht. Sie könnten genauso gut tausend Fragen stellen, und es wäre immer noch völlig irrelevant, da dies nicht der Punkt dieser Antwort ist, mit der ich klarstelle, dass ich einverstanden bin.
Wtower
1
@Wtower Dies ist nur eine Erklärung der Funktionsweise get_object_or_404und keine bevorzugte Methode, um zu überprüfen, ob Elemente in einem Abfragesatz vorhanden sind. Wenn Sie list () in einem Abfragesatz ausführen, werden alle Objekte in einem Abfragesatz abgerufen. Dies wäre schlimmer, als zweimal abzufragen, wenn viele Zeilen zurückgegeben werden.
Minmaxavg
1
Eine detailliertere Antwort finden Sie in der folgenden Antwort von @ leonid-shvechikov: Die Verwendung .exists()ist effizienter, wenn das qs nicht ausgewertet wird.
Guival
191

Seit Version 1.2 verfügt Django über QuerySet. existiert () Methode, die am effizientesten ist:

if orgs.exists():
    # Do this...
else:
    # Do that...

Wenn Sie QuerySet trotzdem evaluieren möchten, ist es besser, Folgendes zu verwenden:

if orgs:
   ...

Weitere Informationen finden Sie in der Dokumentation zu QuerySet.exists () .

Leonid Shvechikov
quelle
.exists () ist nur für .filter (), gibt es etwas für .get ()?
Rolle
.getgibt kein Abfrageset zurück. Es gibt ein Objekt zurück. Also google dafür
Aseem
Es ist nur spürbar effizienter, wenn Sie ein großes QuerySet haben: docs.djangoproject.com/de/2.1/ref/models/querysets/#exists
Nathan Jones
15

Wenn Sie eine große Anzahl von Objekten haben, kann dies (manchmal) viel schneller sein:

try:
    orgs[0]
    # If you get here, it exists...
except IndexError:
    # Doesn't exist!

An einem Projekt, an dem ich mit einer riesigen Datenbank not orgsarbeite , sind es mehr als 400 ms und 250 ms orgs.count(). In meinen häufigsten Anwendungsfällen (bei denen Ergebnisse vorliegen) wird diese Technik häufig auf unter 20 ms reduziert. (Ein Fall, den ich gefunden habe, war 6.)

Kann natürlich viel länger dauern, je nachdem, wie weit die Datenbank suchen muss, um ein Ergebnis zu finden. Oder noch schneller, wenn es schnell einen findet; YMMV.

BEARBEITEN: Dies ist häufig langsamer als orgs.count()wenn das Ergebnis nicht gefunden wird, insbesondere wenn die Bedingung, nach der Sie filtern, selten ist. Daher ist es besonders nützlich in Ansichtsfunktionen, bei denen Sie sicherstellen müssen, dass die Ansicht vorhanden ist, oder Http404 auslösen müssen. (Wo, wie man hoffen würde, Leute nach URLs fragen, die öfter existieren als nicht.)

Adam Playford
quelle
10

So überprüfen Sie die Leere eines Abfragesatzes:

if orgs.exists():
    # Do something

oder Sie können nach dem ersten Element in einem Abfragesatz suchen. Wenn es nicht vorhanden ist, wird Folgendes zurückgegeben None:

if orgs.first():
    # Do something
Tuss4
quelle
6
if orgs.exists()wurde durch eine Antwort abgedeckt , die etwa 5 Jahre vor dieser gegeben wurde. Das einzige, was diese Antwort auf den Tisch bringt, was vielleicht neu ist, ist if orgs.first(). (Auch dies ist umstritten: Unterscheidet es sich wesentlich von dem orgs[0] vor etwa 5 Jahren vorgeschlagenen ?) Sie sollten diesen Teil der Antwort entwickeln: Wann möchte man dies anstelle der anderen zuvor vorgeschlagenen Lösungen tun ?
Louis
9

Der effizienteste Weg (vor Django 1.2) ist folgender:

if orgs.count() == 0:
    # no results
else:
    # alrigh! let's continue...
Bartosz
quelle
5
.exists () scheint noch effizienter zu sein
dzida
5
Nur dass .exists () einige Monate nach meinem Kommentar hinzugefügt wurde und Django 1.2 (das diese API enthielt) ~ 8 Monate später veröffentlicht wurde. Aber danke, dass Sie nicht abgestimmt haben und sich nicht die Mühe gemacht haben, die Fakten zu überprüfen.
Bartosz
4
Entschuldigung, ich habe Ihrer Antwort eine kleine Änderung hinzugefügt, um sie genauer zu machen und positiv zu stimmen.
Dzida
4

Ich bin mit dem Prädikat nicht einverstanden

if not orgs:

Es sollte sein

if not orgs.count():

Ich hatte das gleiche Problem mit einer ziemlich großen Ergebnismenge (~ 150.000 Ergebnisse). Der Operator ist in QuerySet nicht überladen, daher wird das Ergebnis tatsächlich als Liste entpackt, bevor die Prüfung durchgeführt wird. In meinem Fall hat sich die Ausführungszeit um drei Aufträge verkürzt.

Hedleyroos
quelle
6
__nonzero__ ist in QuerySet bereits überladen. Wenn das Ergebnis nicht zwischengespeichert wird (es wird nie bei der ersten Verwendung des Abfragesatzes verwendet), besteht das Verhalten von __nonzero__ darin, alle Elemente im Abfragesatz zu durchlaufen. Dies ist sehr schlecht, wenn das Set groß ist.
Hedleyroos
0

Sie können auch Folgendes verwenden:

if(not(orgs)): #if orgs is empty else: #if orgs is not empty

Rupesh Chaudhari
quelle