2009-09-07 7 views
104

Was ist das empfohlene Idiom für die Überprüfung, ob eine Abfrage Ergebnisse zurückgegeben hat?
Beispiel:Überprüfen auf leere Abfrage in Django

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 sind dies verschiedene Möglichkeiten zu prüfen, aber ich würde gerne wissen, wie ein erfahrener Django Benutzer es tun würde. Die meisten Beispiele in der Dokumentation nur den Fall ignorieren, wo nichts gefunden wurde ...

Antwort

101
if not orgs: 
    # Do this... 
else: 
    # Do that... 
+3

Diese scheint auch in der Dokumentation bevorzugt zu sein, zum Beispiel: https: // docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7 – Wtower

+0

@Wtower Der Code, auf den Sie sich beziehen, hat für den Vertrag 404 zu erzeugen, wenn der Filterausdruck keine Datensätze trifft oder eine "Liste" des Ergebnisses erzeugt, wenn Es gibt Aufzeichnungen. Der Code dort wird die Datenbank nur einmal treffen. Wenn sie 'exist()' oder 'count()' verwenden, um zuerst zu überprüfen, ob Datensätze zurückgegeben werden, treffen sie die Datenbank zweimal (einmal, um sie zu überprüfen, einmal, um die Datensätze zu erhalten). Dies ist eine spezifische Situation. Es bedeutet nicht, dass im * allgemeinen Fall * die bevorzugte Methode, um zu wissen, ob eine Abfrage Datensätze zurückgibt, do 'if queryset: ... ' – Louis

+1

@Louis ist der Code, auf den ich mich beziehe, ist nur ein Beispiel, das es enthält eine Zeile 'if not my_objects:' um zu demonstrieren, dass dies in den Dokumenten so ist. Alles andere ist völlig irrelevant, deshalb verstehe ich Ihre Meinung nicht. Sie könnten auch tausend Fragen stellen und es wäre immer noch völlig irrelevant, da dies nicht der Sinn dieser Antwort ist, mit der ich klarstelle, dass ich dem zustimme. – Wtower

3

Der effizienteste Weg (vor django 1.2), ist dies:

if orgs.count() == 0: 
    # no results 
else: 
    # alrigh! let's continue... 
+3

.exists() scheint noch effizienter zu sein – dzida

+3

Außer dass .exists() wurde einige Monate nach meinem Kommentar hinzugefügt, und Django 1.2 (die diese API enthalten) wurde ~ 8 Monate später veröffentlicht. Aber danke fürs Abstimmen und nicht um 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 wählen. – dzida

14

Wenn Sie eine große Anzahl von Objekte, kann diese (zeitweise) viel schneller sein:

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

bei einem Projekt mit einer großen Datenbank auf ich arbeite, not orgs ist 400+ ms und orgs.count() ist 25 0 ms. In meinen häufigsten Anwendungsfällen (bei denen Ergebnisse vorliegen) wird diese Technik oft auf unter 20 ms reduziert. (Ein Fall, den ich fand, war es 6.)

Könnte natürlich viel länger sein, abhängig davon, wie weit die Datenbank suchen muss, um ein Ergebnis zu finden. Oder noch schneller, wenn es schnell gefunden wird; YMMV.

EDIT: Diese wird oft langsamer als orgs.count(), wenn das Ergebnis nicht gefunden wird, insbesondere wenn die Bedingung, die Sie filtern, ist eine seltene; Daher ist es besonders nützlich in Ansichtsfunktionen, in denen Sie sicherstellen müssen, dass die Ansicht existiert oder Http404. (Wo würde man hoffen, dass Leute nach URLs fragen, die häufiger existieren als nicht.)

134

Seit Version 1.2 hat Django QuerySet. exists() Verfahren, das ist der effizienteste:

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

Aber wenn Sie QuerySet gehen zu bewerten sowieso ist es besser zu nutzen:

if orgs: 
    ... 

Weitere Informationen read QuerySet.exists() documentation.

5

Ich bin nicht einverstanden mit dem Prädikat

if not orgs: 

Es sollte

seine
if not orgs.count(): 

Ich war mit einer ziemlich großen Ergebnismenge das gleiche Problem mit (~ 150k Ergebnissen). Der Operator wird in QuerySet nicht überladen, daher wird das Ergebnis vor der Prüfung tatsächlich als Liste ausgepackt. In meinem Fall ging die Ausführungszeit um drei Bestellungen zurück.

+4

_ \ _ ungleich Null _ \ _ ist in QuerySet bereits überladen. Wenn das Ergebnis nicht zwischengespeichert wird (bei der ersten Verwendung des Abfrage-Sets wird es nie verwendet), wird das Verhalten von _ \ _ nonzero _ \ _ über alle Elemente im Abfrage-Set iteriert. Dies ist sehr schlecht, wenn das Set groß ist. – hedleyroos

9

die Leere eines queryset Um zu überprüfen:

if orgs.exists(): 
    # Do something 

oder Sie können in einem queryset für den ersten Punkt überprüfen, ob sie es None kehrt existiert nicht:

if orgs.first(): 
    # Do something 
+1

'if orgs.exists()' wurde von einer [Antwort] (http://stackoverflow.com/a/2373793/1906307) abgedeckt, die etwa 5 Jahre vor dieser bereitgestellt wurde. Das einzige, was diese Antwort zu der Tabelle bringt, die * vielleicht * neu ist, ist 'if orgs.first()'. (Auch das ist fraglich: unterscheidet es sich wesentlich von den 'orgs [0]' [vorgeschlagen] (http://stackoverflow.com/a/2098092/1906307) vor ungefähr 5 Jahren?) Sie sollten diesen Teil entwickeln der antwort: wann möchte man das ** anstelle von ** den anderen vorgeschlagenen lösungen machen? – Louis