Gibt es eine Django-Funktion, mit der ich ein Objekt aus der Datenbank abrufen kann, oder Keine, wenn nichts übereinstimmt?
Im Moment benutze ich so etwas wie:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Aber das ist nicht sehr klar und es ist chaotisch, überall zu haben.
len(foo)
ist schlecht : " Hinweis: Verwenden Sie len () nicht für QuerySets, wenn Sie nur die Anzahl der Datensätze in der Gruppe bestimmen möchten. Es ist viel effizienter, eine Zählung auf Datenbankebene mithilfe von SQLs SELECT COUNT zu verarbeiten (), und Django bietet genau aus diesem Grund eine count () -Methode. " Umgeschrieben:foo = foo[0] if foo.exists() else None
first()
: PAntworten:
In Django 1.6 können Sie die
first()
Queryset-Methode verwenden. Es gibt das erste Objekt zurück, das mit dem Abfragesatz übereinstimmt, oder None, wenn kein übereinstimmendes Objekt vorhanden ist.Verwendung:
quelle
MultipleObjectsReturned()
wird dies nicht ausgelöst, wie hier dokumentiert . Sie können einige bessere Antworten finden hierfirst()
funktioniert genau so, wie es angenommen wird. Es gibt das erste Objekt im Abfrageergebnis zurück und kümmert sich nicht darum, ob mehrere Ergebnisse gefunden werden. Wenn Sie nach mehreren zurückgegebenen Objekten suchen müssen, sollten Sie.get()
stattdessen verwenden..get()
ist nicht für seine Bedürfnisse geeignet. Die richtige Antwort auf diese Frage finden Sie unten bei @kaapstorm und ist eindeutig die geeignetere Antwort. Missbrauch auffilter()
diese Weise kann zu unerwarteten Konsequenzen führen, was OP wahrscheinlich nichtMultipleObjectsReturned()
. Wenn nicht erwartet wird, dass das zurückgegebene Ergebnis mehrere Objekte zurückgibt, sollte es nicht als solches behandelt werden. Es gab eine lange Debatte darüber hierEs gibt zwei Möglichkeiten, dies zu tun.
Oder Sie können einen Wrapper verwenden:
Nennen Sie es so
quelle
queryset
vor 1.6 keine Methode dafür bereitgestellt haben! Aber dieses Konstrukt ist einfach ungeschickt. Es ist nicht "böse", weil es ein Tutorial-Autor Ihrer Lieblingssprache gesagt hat. Versuchen Sie es mit Google: "Bitte um Vergebung anstatt um Erlaubnis".get
Methode soll nicht zurückkehrenNone
, daher ist eine Ausnahme sinnvoll. Sie sollten es in Fällen verwenden, in denen Sie sicher sind, dass das Objekt dort sein wird / das Objekt "dort sein soll". Auch die Verwendung solcher Ausnahmen wird als "in Ordnung" angesehen, da dies sinnvoll ist. Sie möchten einen Vertragget
mit einem anderen Vertrag, also fangen Sie die Ausnahme ab und unterdrücken sie. Dies ist die Änderung, nach der Sie suchen.Um der Antwort von sorki einen Beispielcode hinzuzufügen (ich würde dies als Kommentar hinzufügen, aber dies ist mein erster Beitrag, und ich habe nicht genug Ruf, um Kommentare zu hinterlassen), habe ich einen benutzerdefinierten Manager get_or_none wie folgt implementiert:
Und jetzt kann ich das machen:
quelle
Sie können auch versuchen, Django ärgerlich zu verwenden (es hat andere nützliche Funktionen!)
Installieren Sie es mit:
quelle
Geben Sie Foo seinen benutzerdefinierten Manager . Es ist ziemlich einfach - setzen Sie Ihren Code einfach im benutzerdefinierten Manager in Funktion, legen Sie den benutzerdefinierten Manager in Ihrem Modell fest und rufen Sie ihn mit auf
Foo.objects.your_new_func(...)
.Wenn Sie eine generische Funktion benötigen (um sie auf jedem Modell zu verwenden, nicht nur mit dem benutzerdefinierten Manager), schreiben Sie Ihre eigene und platzieren Sie sie irgendwo auf Ihrem Python-Pfad und importieren Sie sie, nicht mehr chaotisch.
quelle
Unabhängig davon, ob Sie dies über einen Manager oder eine generische Funktion tun, möchten Sie möglicherweise auch 'MultipleObjectsReturned' in der TRY-Anweisung abfangen, da die Funktion get () dies auslöst, wenn Ihre kwargs mehr als ein Objekt abrufen.
Aufbauend auf der generischen Funktion:
und im Manager:
quelle
Hier ist eine Variation der Hilfsfunktion, mit der Sie optional eine
QuerySet
Instanz übergeben können, falls Sie das eindeutige Objekt (falls vorhanden) aus einem anderen Abfragesatz als dem Objektabfragesatz des Modellsall
abrufen möchten (z. B. aus einer Teilmenge von untergeordneten Elementen, die zu a gehören übergeordnete Instanz):Dies kann auf zwei Arten verwendet werden, z.
obj = get_unique_or_none(Model, *args, **kwargs)
wie zuvor besprochenobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
quelle
Ich denke, dass Sie in den meisten Fällen nur Folgendes verwenden können:
Nur wenn es nicht kritisch ist, dass ein neuer Eintrag in die Foo-Tabelle eingefügt wird (andere Spalten haben die Werte Keine / Standard).
quelle