163 votes

Django filter versus get pour un seul objet ?

J'ai eu un débat à ce sujet avec quelques collègues. Existe-t-il un moyen privilégié de récupérer un objet dans Django lorsque l'on n'en attend qu'un seul ?

Les deux moyens les plus évidents sont :

   try: 
      obj = MyModel.objects.get(id=1)
   except MyModel.DoesNotExist:
      # we have no object!  do something
      pass

et

   objs = MyModel.objects.filter(id=1)
   if len(objs) == 1:
      obj = objs[0]
   else: 
      # we have no object!  do something
      pass

La première méthode semble plus correcte d'un point de vue comportemental, mais utilise des exceptions dans le flux de contrôle, ce qui peut introduire une certaine surcharge. La seconde est plus détournée mais ne lève jamais d'exception.

Avez-vous une idée de ce qui est préférable ? Laquelle est la plus efficace ?

201voto

James Bennett Points 6318

get() est prévu spécifiquement pour ce cas. Utilisez-le.

L'option 2 correspond presque exactement à la façon dont l get() est en fait implémentée dans Django, il ne devrait donc pas y avoir de différence de "performance" (et le fait que vous y pensiez indique que vous violez l'une des règles cardinales de la programmation, à savoir essayer d'optimiser le code avant même qu'il n'ait été écrit et profilé - tant que vous n'avez pas le code et que vous ne pouvez pas l'exécuter, vous ne savez pas comment il se comportera, et essayer d'optimiser avant cela est un parcours du combattant).

31voto

priestc Points 5002

Vous pouvez installer un module appelé django-annoying et ensuite faire ça :

from annoying.functions import get_object_or_None

obj = get_object_or_None(MyModel, id=1)

if not obj:
    #omg the object was not found do some error stuff

18voto

1 est correct. En Python, une exception a le même coût qu'un retour. Pour une preuve simplifiée, vous pouvez consulter este .

2 C'est ce que fait Django dans le backend. get appelle filter et lève une exception si aucun objet n'est trouvé ou si plus d'un objet est trouvé.

15voto

badcat Points 6262

Je suis un peu en retard sur la fête, mais avec Django 1.6, il y a la fonction first() sur les querysets.

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#django.db.models.query.QuerySet.first


Renvoie le premier objet correspondant au queryset, ou None s'il n'y a pas d'objet correspondant. Si l'ensemble de requêtes n'a pas d'ordre défini, l'ensemble de requêtes est automatiquement ordonné par la clé primaire.

Ejemplo:

p = Article.objects.order_by('title', 'pub_date').first()
Note that first() is a convenience method, the following code sample is equivalent to the above example:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None

9voto

krubo Points 927

Pourquoi faire tout ce travail ? Remplacer 4 lignes par un raccourci intégré. (Ceci fait son propre try/except).

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)

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