it-swarm.com.de

Der schnellste Weg, um das erste Objekt aus einem Abfragesatz in Django zu erhalten?

Häufig möchte ich das erste Objekt aus einem Abfragesatz in Django abrufen oder None zurückgeben, wenn es keine gibt. Dafür gibt es viele Möglichkeiten, die alle funktionieren. Aber ich frage mich, welches die leistungsfähigste ist.

qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
    return qs[0]
else:
    return None

Führt dies zu zwei Datenbankaufrufen? Das scheint verschwenderisch. Geht das noch schneller?

qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
    return qs[0]
else:
    return None

Eine andere Option wäre:

qs = MyModel.objects.filter(blah = blah)
try:
    return qs[0]
except IndexError:
    return None

Dies erzeugt einen einzelnen Datenbankaufruf, was gut ist. Es ist jedoch häufig erforderlich, ein Ausnahmeobjekt zu erstellen. Dies ist sehr speicherintensiv, wenn Sie nur einen einfachen If-Test benötigen.

Wie kann ich dies mit nur einem Datenbankaufruf und ohne Speicherabbau mit Ausnahmeobjekten tun?

172
Leopd

Django 1.6 (veröffentlicht im November 2013) führte die Convenience-Methodenfirst() und last() ein, die die resultierende Ausnahme schlucken und None wenn das Queryset keine Objekte zurückgibt.

300
cod3monk3y

Die richtige Antwort ist

Entry.objects.all()[:1].get()

Kann verwendet werden in:

Entry.objects.filter()[:1].get()

Sie möchten es nicht zuerst in eine Liste umwandeln, da dies einen vollständigen Datenbankaufruf aller Datensätze erzwingen würde. Führen Sie einfach die obigen Schritte aus, und es wird nur der erste ausgeführt. Sie können sogar .order_by Verwenden, um sicherzustellen, dass Sie das erste erhalten, das Sie möchten.

Stellen Sie sicher, dass Sie die Funktion .get() hinzufügen. Andernfalls wird ein QuerySet zurückgegeben und kein Objekt.

135
stormlifter
r = list(qs[:1])
if r:
  return r[0]
return None

Jetzt haben Sie in Django 1.9 die Methode first() für Abfragesätze.

YourModel.objects.all().first()

Dies ist ein besserer Weg als .get() oder [0], Da keine Ausnahme ausgelöst wird, wenn der Abfragesatz leer ist. Daher müssen Sie nicht mit exists() prüfen.

30
levi

Wenn Sie das erste Element häufig abrufen möchten, können Sie QuerySet in diese Richtung erweitern:

class FirstQuerySet(models.query.QuerySet):
    def first(self):
        return self[0]


class ManagerWithFirstQuery(models.Manager):
    def get_query_set(self):
        return FirstQuerySet(self.model)

Modell wie folgt definieren:

class MyModel(models.Model):
    objects = ManagerWithFirstQuery()

Und benutze es so:

 first_object = MyModel.objects.filter(x=100).first()
7
Nikolay Fominyh

Es kann so sein

obj = model.objects.filter(id=emp_id)[0]

oder

obj = model.objects.latest('id')
5
Nauman Tariq

Das könnte auch funktionieren:

def get_first_element(MyModel):
    my_query = MyModel.objects.all()
    return my_query[:1]

wenn es leer ist, wird eine leere Liste zurückgegeben. Andernfalls wird das erste Element in einer Liste zurückgegeben.

4
Nick Cuevas

Sie sollten Django Methoden verwenden, wie es existiert. Es ist für Sie da, um es zu verwenden.

if qs.exists():
    return qs[0]
return None
3
Ari

Seit Django 1.6 können Sie filter () mit first () wie folgt verwenden:

Model.objects.filter(field_name=some_param).first()
0
dtar