2009-09-07 8 views
104

Quel est l'idiome recommandé pour vérifier si une requête a renvoyé des résultats?
Exemple:Vérification du jeu de requête vide dans Django

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc') 
# If any results 
    # Do this with the results without querying again. 
# Else, do something else... 

Je suppose qu'il ya plusieurs façons de vérifier, mais je voudrais savoir comment un utilisateur expérimenté Django le ferait. La plupart des exemples dans la documentation ignorer le cas où rien n'a été trouvé ...

Répondre

101
if not orgs: 
    # Do this... 
else: 
    # Do that... 
+3

Cette semble également être préféré dans la documentation, par exemple: https: // docs.djangoproject.com/fr/1.8/topics/http/shortcuts/#id7 – Wtower

+0

@Wtower Le code auquel vous faites référence a pour contrat d'élever 404 si l'expression de filtrage ne frappe aucun enregistrement ou de produire une 'liste' du résultat si il y a des enregistrements. Le code là va frapper la base de données juste une fois. S'ils ont utilisé 'exist()' ou 'count()' pour vérifier d'abord s'il y a des enregistrements retournés, ils vont frapper deux fois la base de données (une fois pour vérifier, une fois pour obtenir les enregistrements). C'est une situation spécifique. Il n'implique pas que dans le * cas général *, la méthode préférée pour savoir si une requête retournera des enregistrements est d'utiliser faire si 'queryset: ...' – Louis

+1

@Louis le code auquel je me réfère est seulement un exemple qu'il contient une ligne 'sinon my_objects:' pour montrer que c'est comme ça qu'ils le font dans les docs. Tout le reste est totalement hors de propos, donc je ne comprends pas votre point. Ils pourraient aussi faire mille requêtes et ce serait tout à fait hors de propos car ce n'est pas le but de cette réponse, avec laquelle je précise que je suis d'accord. – Wtower

3

La façon la plus efficace (avant django 1.2) est la suivante:

if orgs.count() == 0: 
    # no results 
else: 
    # alrigh! let's continue... 
+3

.exists() semble être encore plus efficace – dzida

+3

Sauf que .exists() a été ajouté quelques mois après mon commentaire, et Django 1.2 (qui a incorporé cette API) a été publié ~ 8 mois plus tard. Mais merci pour le vote à la baisse et ne pas prendre la peine de vérifier les faits. – Bartosz

+4

Désolé, j'ai ajouté un petit edit à votre réponse pour le rendre plus précis et voté positivement. – dzida

14

Si vous avez un grand nombre de objets, cela peut (parfois) être beaucoup plus rapide:

try: 
    orgs[0] 
    # If you get here, it exists... 
except IndexError: 
    # Doesn't exist! 

sur un projet, je travaille avec une base de données énorme, not orgs est plus de 400 ms et orgs.count() est 25 0ms. Dans mes cas d'utilisation les plus courants (ceux où il y a des résultats), cette technique descend souvent à moins de 20 ms. (Un cas que j'ai trouvé, il était 6.)

Pourrait être beaucoup plus long, bien sûr, en fonction de quelle distance la base de données doit chercher pour trouver un résultat. Ou même plus vite, s'il en trouve un rapidement; YMMV.

EDIT: Ce sera souvent être plus lent que orgs.count() si le résultat est introuvable, en particulier si la condition sur laquelle vous filtrez est rare; par conséquent, il est particulièrement utile dans les fonctions de vue où vous devez vous assurer que la vue existe ou lancer Http404. (Où, on peut l'espérer, les gens demandent des URL qui existent le plus souvent.)

134

Depuis la version 1.2, Django a QuerySet. exists() méthode qui est le plus efficace:

if orgs.exists(): 
    # Do this... 
else: 
    # Do that... 

Mais si vous allez évaluer QuerySet de toute façon, il est préférable d'utiliser:

if orgs: 
    ... 

Pour plus d'informations read QuerySet.exists() documentation.

5

Je suis en désaccord avec le prédicat

if not orgs: 

Il devrait être

if not orgs.count(): 

j'avais le même problème avec un jeu de résultats assez grande (~ résultats de 150k). L'opérateur n'est pas surchargé dans QuerySet, donc le résultat est décompressé en tant que liste avant la vérification. Dans mon cas, le temps d'exécution a diminué de trois ordres.

+4

_ \ _ nonzero _ \ _ est déjà surchargé dans QuerySet. Si le résultat n'est pas mis en cache (il ne l'est jamais lors de la première utilisation du jeu de requête), le comportement de _ \ _ nonzero _ \ _ consiste à parcourir tous les éléments du jeu de requête. C'est très mauvais si l'ensemble est grand. – hedleyroos

9

Pour vérifier le vide d'un queryset:

if orgs.exists(): 
    # Do something 

ou vous pouvez vérifier un premier élément dans une queryset, si elle n'existe pas il retournera None:

if orgs.first(): 
    # Do something 
+1

'si orgs.exists()' était couvert par une [réponse] (http://stackoverflow.com/a/2373793/1906307) qui a été fournie environ 5 ans avant celle-ci. La seule chose que cette réponse apporte à la table qui est * peut-être nouvelle est "si orgs.first()". (Même cela est discutable: est-ce que c'est sensiblement différent de faire le 'orgs [0]' [suggéré] (http://stackoverflow.com/a/2098092/1906307) il y a environ 5 ans aussi?) Vous devriez développer cette partie de la réponse: quand voudrait-on faire cela ** au lieu de ** les autres solutions proposées plus tôt? – Louis

Questions connexes