Lorsque je demande au gestionnaire de modèles d'obtenir un objet, il soulève DoesNotExist
lorsqu'il n'y a pas d'objet correspondant.
go = Content.objects.get(name="baby")
Au lieu de DoesNotExist
, comment puis-je avoir go
être None
à la place?
Il n'y a pas de moyen "intégré" de le faire. Django lèvera l'exception DoesNotExist à chaque fois. La manière idiomatique de gérer cela dans python consiste à l'envelopper dans un catch try:
try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None
Ce que j'ai fait est de sous-classer models.Manager, créez un safe_get
comme le code ci-dessus et utilisez ce gestionnaire pour mes modèles. De cette façon, vous pourrez écrire: SomeModel.objects.safe_get(foo='bar')
.
Depuis Django 1.6, vous pouvez utiliser la méthode first () () comme ceci:
Content.objects.filter(name="baby").first()
get()
déclenche une exceptionDoesNotExist
si un objet n'est pas trouvé pour les paramètres donnés. Cette exception est également un attribut de la classe de modèle. L'exceptionDoesNotExist
hérite deDjango.core.exceptions.ObjectDoesNotExist
Vous pouvez intercepter l'exception et affecter None
à aller.
from Django.core.exceptions import ObjectDoesNotExist
try:
go = Content.objects.get(name="baby")
except ObjectDoesNotExist:
go = None
Vous pouvez créer une fonction générique pour cela.
def get_or_none(classmodel, **kwargs):
try:
return classmodel.objects.get(**kwargs)
except classmodel.DoesNotExist:
return None
Utilisez ceci comme ci-dessous:
go = get_or_none(Content,name="baby")
go sera No si aucune entrée ne correspond, sinon, l'entrée sera renvoyée au contenu.
Remarque: L'exception MultipleObjectsReturned sera levée si plusieurs entrées sont renvoyées pour name = "baby".
Vous pouvez le faire de cette façon:
go = Content.objects.filter(name="baby").first()
Maintenant, la variable go pourrait être soit l'objet que vous voulez, soit aucun
Réf.: https://docs.djangoproject.com/fr/1.8/ref/models/querysets/#Django.db.models.query.QuerySet.first
Pour faciliter les choses, voici un extrait du code que j'ai écrit, basé sur les contributions des réponses merveilleuses ici:
class MyManager(models.Manager):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except ObjectDoesNotExist:
return None
Et puis dans votre modèle:
class MyModel(models.Model):
objects = MyManager()
C'est ça. Maintenant, vous avez MyModel.objects.get () ainsi que MyModel.objetcs.get_or_none ()
vous pouvez utiliser exists
avec un filtre:
Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS
juste une alternative pour si vous voulez seulement savoir s'il existe
C'est un de ces fonctions gênantes que vous ne voudrez peut-être pas ré-implémenter:
from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
La gestion des exceptions à différents points de votre vue peut s'avérer fastidieuse. Pourquoi ne pas définir un gestionnaire de modèles personnalisé, dans le fichier models.py, comme
class ContentManager(model.Manager):
def get_nicely(self, **kwargs):
try:
return self.get(kwargs)
except(KeyError, Content.DoesNotExist):
return None
puis en l'incluant dans la classe de contenu
class Content(model.Model):
...
objects = ContentManager()
De cette façon, il peut être facilement traité dans les vues, c'est-à-dire.
post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist
Si vous souhaitez une solution simple à une ligne ne comportant pas de gestion des exceptions, d'instructions conditionnelles ni d'exigence de Django 1.6+, procédez comme suit:
x = next(iter(SomeModel.objects.filter(foo='bar')), None)
Je pense que ce n'est pas une mauvaise idée d'utiliser 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)
Cet exemple est équivalent à:
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.")
Vous pouvez en savoir plus sur get_object_or_404 () dans Django documentation en ligne.
Nous pouvons utiliser l’exception intégrée Django qui est associée aux modèles nommés .DoesNotExist
. Nous n’avons donc pas à importer une exception ObjectDoesNotExist
.
Au lieu de faire:
from Django.core.exceptions import ObjectDoesNotExist
try:
content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
content = None
Nous pouvons le faire:
try:
content = Content.objects.get(name="baby")
except Content.DoesNotExist:
content = None
À partir de Django 1.7, vous pouvez faire comme:
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):
...
L'avantage de "MyQuerySet.as_manager ()" est que les deux opérations suivantes fonctionneront:
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
Voici une variante de la fonction d'assistance qui vous permet de passer éventuellement une instance QuerySet
au cas où vous souhaiteriez obtenir l'objet unique (le cas échéant) à partir d'un jeu de requête autre que les objets all
du modèle. par exemple à partir d'un sous-ensemble d'éléments enfants appartenant à une instance parent):
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
Ceci peut être utilisé de deux manières, par exemple:
obj = get_unique_or_none(Model, **kwargs)
comme discuté précédemmentobj = get_unique_or_none(Model, parent.children, **kwargs)
Sans exception:
if SomeModel.objects.filter(foo='bar').exists():
x = SomeModel.objects.get(foo='bar')
else:
x = None
En utilisant une exception:
try:
x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
x = None
Il y a un peu d'argument à propos du moment où on devrait utiliser une exception en python. D'une part, "il est plus facile de demander pardon que d'obtenir une permission". Bien que je sois d’accord avec cela, j’estime qu’une exception devrait rester, eh bien, l’exception, et le "cas idéal" devrait fonctionner sans en heurter un.