A menudo me encuentro con ganas de obtener el primer objeto de un conjunto de consultas en Django, o regresar None
si no hay ninguno. Hay muchas maneras de hacer esto que funcionan. Pero me pregunto cuál es el más eficaz.
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
¿Esto resulta en dos llamadas a la base de datos? Eso parece un desperdicio. ¿Es esto más rápido?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
Otra opción sería:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
Esto genera una sola llamada a la base de datos, lo cual es bueno. Pero requiere crear un objeto de excepción la mayor parte del tiempo, lo cual es una tarea que requiere mucha memoria cuando todo lo que realmente necesita es una prueba trivial if.
¿Cómo puedo hacer esto con una sola llamada a la base de datos y sin agitar la memoria con objetos de excepción?
len()
en conjuntos de consultas, use siempre.count()
.first()
ylast()
conveniencia métodos: docs.djangoproject.com/en/dev/ref/models/querysets/#firstRespuestas:
Django 1.6 (lanzado en noviembre de 2013) introdujo los métodos de conveniencia
first()
y selast()
traga la excepción resultante y regresaNone
si el conjunto de consultas no devuelve objetos.fuente
first()
ylast()
hacer cumplir unaORDER BY
cláusula en una consulta. Hará que los resultados sean deterministas, pero probablemente disminuirá la velocidad de la consulta.La respuesta correcta es
Que se puede usar en:
No querrás convertirlo primero en una lista porque eso forzaría una llamada a la base de datos completa de todos los registros. Simplemente haga lo anterior y solo extraerá el primero. Incluso podría usar
.order_by
para asegurarse de obtener lo primero que desea.Asegúrese de agregar
.get()
o de lo contrario obtendrá un QuerySet y no un objeto.fuente
Entry.objects.all()[0]
?fuente
LIMIT 1
a la consulta, y no sé si puede hacer algo mejor que esto. Sin embargo, a nivel interno__nonzero__
en elQuerySet
que se implementa comotry: iter(self).next() except StopIteration: return false...
para que no se escapen de la excepción.QuerySet.__nonzero__()
nunca se llama ya queQuerySet
se convierte en alist
antes de verificar la veracidad. Sin embargo, aún pueden ocurrir otras excepciones.StopIteration
excepción.__iter__
para obtener un nuevo objeto iterador y llamar a sunext
método hasta queStopIteration
se lance. Así que definitivamente habrá una excepción en alguna parte;)Ahora, en Django 1.9 tienes un
first()
método para conjuntos de consultas.Esta es una mejor manera que
.get()
o[0]
porque no arroja una excepción si el conjunto de consultas está vacío. Por lo tanto, no es necesario verificar usandoexists()
fuente
Si planea obtener el primer elemento con frecuencia, puede extender QuerySet en esta dirección:
Defina un modelo como este:
Y úsalo así:
fuente
Esto podría funcionar también:
si está vacío, devuelve una lista vacía, de lo contrario, devuelve el primer elemento dentro de una lista.
fuente
Puede ser asi
o
fuente
Debe usar métodos django, como existe. Está ahí para que lo uses.
fuente
Desde django 1.6 puede usar filter () con el método first () de esta manera:
fuente