2009-09-07 18 views
104

¿Cuál es el modismo recomendado para comprobar si una consulta arrojó algún resultado?
Ejemplo:Comprobación de queryset vacío en Django

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

supongo que hay varias maneras diferentes de comprobar esto, pero me gustaría saber cómo un usuario experimentado Django lo haría. mayoría de los ejemplos en los documentos simplemente ignorar el caso en que no se encontró nada ...

Respuesta

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

Este parece ser también preferido en la documentación, por ejemplo: https: // docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7 – Wtower

+0

@Wtower El código al que se refiere tiene un contrato para generar 404 si la expresión de filtrado no coincide con ningún registro o produce una 'lista' del resultado si hay registros. El código allí golpeará la base de datos solo una vez. Si usaban 'exists()' o 'count()' para verificar primero si van a haber registros devueltos, estarían golpeando la base de datos dos veces (una para verificar, una para obtener los registros). Esta es una situación específica. No implica que en el * caso general *, el método preferido para saber si una consulta devolverá registros es usar do 'if queryset: ...' – Louis

+1

@Louis el código al que me refiero es solo un ejemplo que contiene una línea 'if not my_objects:' para demostrar que así es como lo hacen en los documentos. Todo lo demás es completamente irrelevante, así que no entiendo tu punto. También podrían hacer mil consultas y aún sería totalmente irrelevante ya que este no es el objetivo de esta respuesta, con lo cual dejo en claro que estoy de acuerdo. – Wtower

3

La forma más eficiente (antes de Django 1.2) es la siguiente:

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

.exists() parece ser incluso más eficiente – dzida

+3

Excepto que .exists() se agregó unos meses después de mi comentario, y Django 1.2 (que incorporó esa API) se publicó ~ 8 meses después. Pero gracias por votar negativamente y no molestarse en verificar los hechos. – Bartosz

+4

Disculpa, agregué una edición pequeña a tu respuesta para que sea más precisa y voté positivamente. – dzida

14

Si usted tiene un gran número de objetos, esto puede (a veces) sean mucho más rápido:

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

en un proyecto que estoy trabajando con una enorme base de datos, not orgs es de 400 ms y es orgs.count() 25 0ms. En mis casos de uso más comunes (aquellos donde hay resultados), esta técnica a menudo baja a menos de 20 ms. (Un caso que encontré, fue 6.)

Podría ser mucho más largo, por supuesto, dependiendo de cuánto debe buscar la base de datos para encontrar un resultado. O incluso más rápido, si encuentra uno rápidamente; YMMV.

EDIT: Esto se menudo ser más lento que orgs.count() si no se encuentra el resultado, sobre todo si la condición que está filtrando en una rara es uno; como resultado, es particularmente útil en las funciones de visualización donde necesita asegurarse de que la vista exista o lanzar Http404. (Donde, uno esperaría, las personas están pidiendo URLs que existen más de las veces).

134

Desde la versión 1.2, Django tiene QuerySet. exists() método que es el más eficiente:

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

Pero si se va a evaluar QuerySet de todos modos es mejor utilizar:

if orgs: 
    ... 

Para obtener más información read QuerySet.exists() documentation.

5

no estoy de acuerdo con el predicado

if not orgs: 

Debe ser

if not orgs.count(): 

que estaba teniendo el mismo problema con un conjunto de resultados bastante grande (~ resultados 150k). El operador no está sobrecargado en QuerySet, por lo que el resultado se desempaqueta como una lista antes de realizar la verificación. En mi caso, el tiempo de ejecución disminuyó en tres órdenes.

+4

_ \ _ nonzero _ \ _ ya está sobrecargado en QuerySet. Si el resultado no está almacenado en la memoria caché (nunca está en el primer uso del conjunto de consulta), el comportamiento de _ \ _ nonzero _ \ _ es iterar sobre todos los elementos en el conjunto de consulta. Esto es muy malo si el conjunto es grande. – hedleyroos

9

Para comprobar el vacío de un conjunto de consultas:

if orgs.exists(): 
    # Do something 

o se puede comprobar si hay un primer elemento de un conjunto de consultas, si no existe volverá None:

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

'if orgs.exists()' estaba cubierto por una [respuesta] (http://stackoverflow.com/a/2373793/1906307) que se proporcionó unos 5 años antes de este. Lo único que esta respuesta aporta a la tabla que es * quizás * nueva es 'if orgs.first()'. (Incluso esto es discutible: ¿es sustancialmente diferente de hacer las 'orgs [0]' [sugeridas] (http://stackoverflow.com/a/2098092/1906307) hace aproximadamente 5 años también?) Usted debe desarrollar esa parte de la respuesta: ¿cuándo querríamos hacer esto ** en lugar de ** las otras soluciones propuestas anteriormente? – Louis

Cuestiones relacionadas