Réponses:
Il n'y a aucun moyen «intégré» de le faire. Django lèvera à chaque fois l'exception DoesNotExist. La façon idiomatique de gérer cela en python est de l'envelopper dans une prise d'essai:
try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None
Ce que j'ai fait, c'est de sous-classer les modèles.Manager, créer un safe_get
comme le code ci-dessus et utiliser ce gestionnaire pour mes modèles. De cette façon , vous pouvez écrire: SomeModel.objects.safe_get(foo='bar')
.
SomeModel.objects.filter(foo='bar').first()
cela renvoie la première correspondance, ou Aucun. Il n'échoue pas s'il y a plusieurs exemples commequeryset.get()
filter().first()
je pense que l'exception est la voie à suivre.
Depuis django 1.6, vous pouvez utiliser la méthode first () comme ceci:
Content.objects.filter(name="baby").first()
get()
lève uneDoesNotExist
exception si aucun objet n'est trouvé pour les paramètres donnés. Cette exception est également un attribut de la classe de modèle. L'DoesNotExist
exception hérite dedjango.core.exceptions.ObjectDoesNotExist
Vous pouvez intercepter l'exception et lui attribuer None
le départ.
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 None si aucune entrée ne correspondra sinon retournera l'entrée Content.
Remarque: Cela déclenche une exception MultipleObjectsReturned si plusieurs entrées sont retournées pour name = "baby"
Vous pouvez le faire de cette façon:
go = Content.objects.filter(name="baby").first()
Maintenant, la variable go peut être soit l'objet que vous voulez, soit None
Réf: https://docs.djangoproject.com/en/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 entrées des merveilleuses réponses 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 tout. Vous avez maintenant 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 si elle existe
exists()
sera utilisé avec la if
clause avant de récupérer l'objet, provoquant ainsi un double coup sur la base de données. Je garderai toujours le commentaire au cas où cela aiderait quelqu'un d'autre.
La gestion des exceptions à différents points de vos vues peut être très compliquée ... Qu'en est-il de la définition d'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 l'inclure dans la classe de modèle de contenu
class Content(model.Model):
...
objects = ContentManager()
De cette façon, il peut être facilement traité dans les vues à savoir
post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist
return self.get(**kwargs)
le faire fonctionner pour moi. Pour ne rien dire de mal avec la réponse, juste un conseil pour quiconque essaie de l'utiliser avec des versions ultérieures (ou avec quoi que ce soit d'autre l'empêchant de fonctionner pour moi).
C'est l'une de ces fonctions ennuyeuses 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")
get_object_or_None
mais j'ai constaté qu'il augmentait toujours MultipleObjectsReturned
si plusieurs objets. Ainsi, l'utilisateur pourrait envisager d'entourer d'un try-except
(que la fonction elle-même a try-except
déjà).
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 équivaut à:
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 la documentation en ligne de django.
À 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 éléments suivants fonctionneront:
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
Voici une variante de la fonction d'assistance qui vous permet de transmettre éventuellement une QuerySet
instance, au cas où vous souhaitez obtenir l'objet unique (s'il est présent) à partir d'un ensemble de requêtes autre que l'ensemble de all
requêtes des objets du modèle (par exemple à partir d'un sous-ensemble d'éléments enfants appartenant à un 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
Cela peut être utilisé de deux manières, par exemple:
obj = get_unique_or_none(Model, **kwargs)
tel que 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
Utilisation d'une exception:
try:
x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
x = None
Il y a un peu d'argument sur le moment où il faut utiliser une exception en python. D'une part, "il est plus facile de demander pardon que de permission". Bien que je sois d'accord avec cela, je crois qu'une exception doit rester, eh bien, l'exception, et le «cas idéal» devrait fonctionner sans en toucher un.
Nous pouvons utiliser l'exception intégrée de Django attachée aux modèles nommés comme .DoesNotExist
. Nous n'avons donc pas à importer d' ObjectDoesNotExist
exception.
Au lieu de cela:
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
Il s'agit d'une copie de get_object_or_404 de Django, sauf que la méthode renvoie None. Ceci est extrêmement utile lorsque nous devons utiliser la only()
requête pour récupérer uniquement certains champs. Cette méthode peut accepter un modèle ou un ensemble de requêtes.
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
Il vaut peut-être mieux utiliser:
User.objects.filter(username=admin_username).exists()