Antworten:
Es gibt keine "eingebaute" Möglichkeit, dies zu tun. Django löst jedes Mal die DoesNotExist-Ausnahme aus. Die idiomatische Möglichkeit, dies in Python zu handhaben, besteht darin, es in einen Try-Catch zu packen:
try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None
Was ich getan habe, ist, Modelle in Unterklassen zu unterteilen. Manager, erstellen Sie einen safe_get
ähnlichen Code wie oben und verwenden Sie diesen Manager für meine Modelle. Auf diese Weise können Sie schreiben : SomeModel.objects.safe_get(foo='bar')
.
SomeModel.objects.filter(foo='bar').first()
das erste Match oder None zurückgeben. Es scheitert nicht, wenn es mehrere Fälle wiequeryset.get()
filter().first()
Ich denke, die Ausnahme ist der richtige Weg.
Seit django 1.6 können Sie die first () -Methode wie folgt verwenden :
Content.objects.filter(name="baby").first()
get()
löst eineDoesNotExist
Ausnahme aus, wenn für die angegebenen Parameter kein Objekt gefunden wird. Diese Ausnahme ist auch ein Attribut der Modellklasse. DieDoesNotExist
Ausnahme erbt vondjango.core.exceptions.ObjectDoesNotExist
Sie können die Ausnahme abfangen und zuweisen None
, um zu gehen.
from django.core.exceptions import ObjectDoesNotExist
try:
go = Content.objects.get(name="baby")
except ObjectDoesNotExist:
go = None
Hierfür können Sie eine generische Funktion anlegen.
def get_or_none(classmodel, **kwargs):
try:
return classmodel.objects.get(**kwargs)
except classmodel.DoesNotExist:
return None
Verwenden Sie dies wie folgt:
go = get_or_none(Content,name="baby")
go ist None, wenn kein anderer Eintrag übereinstimmt, wird der Content-Eintrag zurückgegeben.
Hinweis: Es wird eine Ausnahme ausgelöst. MultipleObjectsReturned, wenn mehr als ein Eintrag für name = "baby" zurückgegeben wird.
Sie können es so machen:
go = Content.objects.filter(name="baby").first()
Jetzt kann die Variable go entweder das gewünschte Objekt oder None sein
Ref: https://docs.djangoproject.com/de/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first
Um die Sache zu vereinfachen, hier ein Ausschnitt des Codes, den ich geschrieben habe, basierend auf den Eingaben aus den wunderbaren Antworten hier:
class MyManager(models.Manager):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except ObjectDoesNotExist:
return None
Und dann in Ihrem Modell:
class MyModel(models.Model):
objects = MyManager()
Das ist es. Jetzt haben Sie MyModel.objects.get () sowie MyModel.objetcs.get_or_none ()
Sie könnten exists
mit einem Filter verwenden:
Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS
Nur eine Alternative, wenn Sie nur wissen möchten, ob es existiert
Note: If you only want to determine if at least one result exists (and don’t need the actual objects), it’s more efficient to use exists().
exists()
wird mit verwendet werden if
Klausel bevor das Objekt daher holen einen doppelten Schlag auf den db verursacht. Ich werde den Kommentar trotzdem behalten, falls er jemand anderem hilft.
Das Behandeln von Ausnahmen an verschiedenen Stellen in Ihren Ansichten kann sehr umständlich sein. Wie wäre es mit dem Definieren eines benutzerdefinierten Modellmanagers in der Datei models.py, z
class ContentManager(model.Manager):
def get_nicely(self, **kwargs):
try:
return self.get(kwargs)
except(KeyError, Content.DoesNotExist):
return None
und dann in die Content Model-Klasse aufnehmen
class Content(model.Model):
...
objects = ContentManager()
Auf diese Weise kann es leicht in den Ansichten behandelt werden, dh
post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist
return self.get(**kwargs)
sie für mich funktioniert. Um nicht zu sagen, dass irgendetwas mit der Antwort nicht stimmt, nur ein Tipp für alle, die versuchen, sie mit späteren Versionen zu verwenden (oder mit was auch immer, was sie davon abgehalten hat, für mich zu funktionieren).
Dies ist eine dieser nervigen Funktionen , die Sie möglicherweise nicht erneut implementieren möchten:
from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
get_object_or_None
aber festgestellt, dass er immer noch ausgelöst wird, MultipleObjectsReturned
wenn mehr als ein Objekt vorhanden ist. Daher könnte der Benutzer in Betracht ziehen, mit a zu umgeben try-except
(was die Funktion selbst try-except
bereits hat).
Ich denke, es ist keine schlechte Idee zu verwenden get_object_or_404()
from django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, pk=1)
Dieses Beispiel entspricht:
from django.http import Http404
def my_view(request):
try:
my_object = MyModel.objects.get(pk=1)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
Weitere Informationen zu get_object_or_404 () finden Sie in der Online-Dokumentation zu django.
Ab Django 1.7 können Sie Folgendes tun:
class MyQuerySet(models.QuerySet):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except self.model.DoesNotExist:
return None
class MyBaseModel(models.Model):
objects = MyQuerySet.as_manager()
class MyModel(MyBaseModel):
...
class AnotherMyModel(MyBaseModel):
...
Der Vorteil von "MyQuerySet.as_manager ()" besteht darin, dass beide der folgenden Funktionen funktionieren:
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
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 Modells all
abrufen möchten (z. B. aus einer Teilmenge von untergeordneten Elementen, die zu a gehören übergeordnete Instanz):
def get_unique_or_none(model, queryset=None, **kwargs):
"""
Performs the query on the specified `queryset`
(defaulting to the `all` queryset of the `model`'s default manager)
and returns the unique object matching the given
keyword arguments. Returns `None` if no match is found.
Throws a `model.MultipleObjectsReturned` exception
if more than one match is found.
"""
if queryset is None:
queryset = model.objects.all()
try:
return queryset.get(**kwargs)
except model.DoesNotExist:
return None
Dies kann auf zwei Arten verwendet werden, z.
obj = get_unique_or_none(Model, **kwargs)
wie zuvor besprochenobj = get_unique_or_none(Model, parent.children, **kwargs)
Ohne Ausnahme:
if SomeModel.objects.filter(foo='bar').exists():
x = SomeModel.objects.get(foo='bar')
else:
x = None
Verwenden einer Ausnahme:
try:
x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
x = None
Es gibt ein wenig Streit darüber, wann man in Python eine Ausnahme verwenden sollte. Einerseits "ist es einfacher, um Vergebung zu bitten als um Erlaubnis". Obwohl ich damit einverstanden bin, glaube ich, dass eine Ausnahme bleiben sollte, nun, die Ausnahme, und der "Idealfall" sollte laufen, ohne eine zu treffen.
Wir können die in Django integrierte Ausnahme verwenden, die an die als .DoesNotExist
. Wir müssen also keine ObjectDoesNotExist
Ausnahme importieren .
Stattdessen tun:
from django.core.exceptions import ObjectDoesNotExist
try:
content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
content = None
Wir können das schaffen:
try:
content = Content.objects.get(name="baby")
except Content.DoesNotExist:
content = None
Dies ist eine Nachahmerin von Djangos get_object_or_404, außer dass die Methode None zurückgibt. Dies ist äußerst nützlich, wenn wir die only()
Abfrage verwenden müssen, um nur bestimmte Felder abzurufen. Diese Methode kann ein Modell oder einen Abfragesatz akzeptieren.
from django.shortcuts import _get_queryset
def get_object_or_none(klass, *args, **kwargs):
"""
Use get() to return an object, or return None if object
does not exist.
klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the get() query.
Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
one object is found.
"""
queryset = _get_queryset(klass)
if not hasattr(queryset, 'get'):
klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
raise ValueError(
"First argument to get_object_or_none() must be a Model, Manager, "
"or QuerySet, not '%s'." % klass__name
)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
return None
Vielleicht ist es besser, wenn Sie verwenden:
User.objects.filter(username=admin_username).exists()