327 votes

Comment obtenir l'objet s'il existe, ou None s'il n'existe pas dans Django ?

Lorsque je demande au gestionnaire de modèle d'obtenir un objet, il soulève la question suivante 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 ?

1voto

Konstantin Points 469

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

La question de savoir quand il faut utiliser une exception en Python fait l'objet d'un débat. D'un côté, "il est plus facile de demander le pardon que la permission". Bien que je sois d'accord avec cela, je pense qu'une exception doit rester, eh bien, l'exception, et le "cas idéal" devrait fonctionner sans en toucher une.

1voto

zakiakhmad Points 305

Nous pouvons utiliser l'exception intégrée de Django qui est attachée aux modèles nommés comme suit .DoesNotExist . Donc, nous n'avons pas besoin d'importer ObjectDoesNotExist exception.

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

1voto

Ersel Er Points 89

J'étais également confronté au même problème. C'est difficile d'écrire et de lire try-except pour chaque fois que vous voulez obtenir un élément de votre modèle comme dans la réponse de @Arthur Debert. Donc, ma solution est de créer un Getter qui est héritée par les modèles :

class Getter:
    @classmethod
    def try_to_get(cls, *args, **kwargs):
        try:
            return cls.objects.get(**kwargs)
        except Exception as e:
            return None

class MyActualModel(models.Model, Getter):
    pk_id = models.AutoField(primary_key=True)
    ...

De cette façon, je peux obtenir l'élément actuel de MyActualModel o None :

MyActualModel.try_to_get(pk_id=1)

1voto

Sihc Points 31

J'utilise Django 2.2.16. Et voici comment je résous ce problème :

from typing import Any

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import Manager

class SManager(Manager):
    def get_if_exist(self, *args: Any, **kwargs: Any):
        try:
            return self.get(*args, **kwargs)
        except ObjectDoesNotExist:
            return None

class SModelBase(ModelBase):
    def _prepare(cls):
        manager = SManager()
        manager.auto_created = True
        cls.add_to_class("objects", manager)

        super()._prepare()

    class Meta:
        abstract = True

class SModel(models.Model, metaclass=SModelBase):
    managers = False

    class Meta:
        abstract = True

Et après cela, dans tous les modèles, il suffit d'importer :

from custom.models import SModel

class SUser(SModel):
    pass

Et dans views vous pouvez appeler comme ceci :

SUser.objects.get_if_exist(id=1)

0voto

pygeek Points 435

Il n'est pas recommandé de donner à x la valeur du type intégré de Python, None. Idéalement, x devrait être une instance du type Django Queryset :

try:
    x = ModelX.objects.get(pk=5) #Django Queryset type
except ModelX.DoesNotExist:
    x = ModelX.objects.none() #Django Empty Queryset type

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X