web-dev-qa-db-fra.com

Comment puis-je obtenir l'objet s'il existe, ou None s'il n'existe pas?

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?

178
TIMEX

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').

280
Arthur Debert

Depuis Django 1.6, vous pouvez utiliser la méthode first () () comme ceci:

Content.objects.filter(name="baby").first()
139
FeroxTL

De Django docs

get() déclenche une exception DoesNotExist 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'exception DoesNotExist hérite de Django.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
30
Amarghosh

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".

27
Ranju R

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

12
Gaurav

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 ()

12
Moti Radomski

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

11
Ryan Saxe

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")
7
mknecht

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
7
Adil Malik

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)
3
blhsing

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.

2
Mohammad Reza

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
1
zakiakhmad

À 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()
1

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:

  1. obj = get_unique_or_none(Model, **kwargs) comme discuté précédemment
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)
1
Gary

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.

1