Quelle est la bonne façon de valider si un objet existe dans une vue django sans renvoyer 404?

91

Je dois vérifier si un objet existe et retourner l'objet, puis en fonction de cela, effectuer des actions. Quelle est la bonne façon de le faire sans retourner une 404?

try:
    listing = RealEstateListing.objects.get(slug_url = slug)
except:
    listing = None

if listing:
Rasiel
la source
Rasiel, puis-je suggérer que vous envisagiez d'accepter l'autre réponse? Cela semble être la bonne façon de procéder, et a été un peu plus votée que la réponse acceptée.
Azendale
1
Je peux le considérer, mais il existe a été introduit dans Django 1.2 qui a été publié le 17 mai 2010, si vous remarquez que ma question a été soumise en 09 ... c'était la bonne réponse à l'époque. Si Exists () est maintenant considéré comme la meilleure façon de le faire, je suppose qu'il serait sémantiquement correct de choisir la deuxième réponse, non?
Rasiel
Rasiel, il est logique que ce soit la bonne réponse à l'époque. Mais les sites stackoverflow semblent être autant axés sur la construction d'un ensemble de bonnes questions / officielles avec les meilleures réponses que les sites trouvent des solutions aux problèmes des gens. D'où ma suggestion de sélectionner ce qui est maintenant la réponse «officiellement correcte».
Azendale
le if listing: devrait être un else:.
Chronial du

Réponses:

116

Je n'utiliserais pas le wrapper 404 si vous ne recevez pas un 404. C'est un abus d'intention. Attrapez simplement DoesNotExist, à la place.

try:
    listing = RealEstateListing.objects.get(slug_url=slug)
except RealEstateListing.DoesNotExist:
    listing = None
ironfroggy
la source
+1: Oui, c'est une meilleure solution que celle acceptée, si vous ne voulez pas du 404.
Carl Meyer
yap, cela semble être la meilleure solution
Rasiel
3
Cette solution fonctionne mieux que exists()si vous devez faire quelque chose avec l'objet.
SaeX
2
J'aime ajouter values_list('id', flat=True). si j'ai juste besoin de voir s'il existelisting = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug)
erajuan
Ce que je trouve étrange dans cette syntaxe, c'est qu'elle RealEstateListing.DoesNotExistfait référence au modèle et non à l'objet lui-même. Pourquoi non RealEstateListing.objects.get(slug_url=slug).DoesNotExist?
Maxim Vallee
198

Vous pouvez également faire:

if not RealEstateListing.objects.filter(slug_url=slug).exists():
    # do stuff...

Parfois, il est plus clair d'utiliser le try: except:bloc et d'autres fois, une seule ligne exists()rend le code plus clair ... tout dépend de la logique de votre application.

zzart
la source
7
c'est la meilleure façon et devrait avoir la réponse
Jharwood
3
Je suppose que exists()cela ne fonctionne pas avec get(), non?
Eduard Luca
8
Notez que cette solution n'est valable que si vous n'allez pas utiliser l'objet en question. Sinon (comme dans le cas des OP), c'est faux et beaucoup plus lent que la solution acceptée: si vous faites un get()plus tard, il enverra une deuxième requête à la base de données.
Chronial du
1
Si vous vérifiez l'existence pour faire quelque chose avec l'objet (s'il existe), alors je préférerai try-exceptà exists().
Jithin Pavithran
7
listing = RealEstateListing.objects.filter(slug_url=slug).first() 
Henrik Heino
la source
2
C'est la meilleure solution si vous devez utiliser l'objet potentiel plus tard, car il ne nécessite qu'une seule affectation et évite d'avoir à utiliser un bloc try / except. Notez que vous pouvez tester l'existence plus tard simplement avecif listing:
Michael Hays
Éviter d'essayer / sauf est une mauvaise pratique. L'un des aspects les plus importants du développement logiciel est la disponibilité pour contrôler les exceptions, afin de pouvoir offrir une bonne expérience utilisateur. Faites savoir aux gens que quelque chose ne fonctionne pas correctement. Seconde; si vous voulez tester l'existence d'un QuerySet, utilisez .exists () sinon c'est un objet. Tester l'existence avec leur clé primaire .... if object.pk: // run code () Cette requête est bien plus rapide que de récupérer toutes les données de l'objet. Vous voulez juste savoir s'il existe.
Wolfgang Leon
2
Il y avait déjà des solutions utilisant try / except et .exists(). Je pense que c'est une bonne idée en SO d'avoir plusieurs réponses différentes sur la façon de faire les choses. C'est peut-être mieux pour ceux qui souhaitent également utiliser l'objet s'il existe. Je ne ferais aucune règle si essayer / sauf doit être évité ou non. Parfois c'est bon, et parfois c'est mauvais par exemple si vous voulez juste faire du code très compact.
Henrik Heino
0

Je le ferais aussi simplement comme suit:

listing = RealEstateListing.objects.filter(slug_url=slug)
if listing:
    # do stuff

Je ne vois pas la nécessité d'essayer / attraper. S'il y a potentiellement plusieurs objets dans le résultat, utilisez first () comme indiqué par l'utilisateur Henrik Heino

Greg Holst
la source
Sauf si vous faites un .first () sur l'ensemble de requêtes ou un .first () dans le conditionnel, cela retournera toujours True.
B.Adler