¿La forma más rápida de obtener el primer objeto de un conjunto de consultas en Django?
A menudo me encuentro deseando obtener el primer objeto de un conjunto de consultas en Django, o devolverlo None
si no hay ninguno. Hay muchas formas de hacer esto y todas funcionan. Pero me pregunto cuál es el de mayor rendimiento.
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
¿Esto da como resultado 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 única 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 requiere mucha memoria cuando todo lo que realmente necesitas es una prueba trivial.
¿Cómo puedo hacer esto con una sola llamada a la base de datos y sin agitar la memoria con objetos de excepción?
Django 1.6 (lanzado en noviembre de 2013) introdujo los métodos convenientes first()
que last()
tragan la excepción resultante y regresan None
si el conjunto de consultas no devuelve ningún objeto.
Puedes utilizar el corte de matrices :
Entry.objects.all()[:1].get()
Que se puede utilizar con .filter()
:
Entry.objects.filter()[:1].get()
No querrás convertirlo primero en una lista porque eso forzaría una llamada completa a la base de datos de todos los registros. Simplemente haga lo anterior y solo extraerá el primero. Incluso podrías usarlo .order_by()
para asegurarte de obtener el primero que deseas.
Asegúrese de agregar el .get()
o, de lo contrario, obtendrá un QuerySet y no un objeto.
Ahora, en Django 1.9 tienes first()
un método para conjuntos de consultas.
YourModel.objects.all().first()
Esta es una mejor manera que .get()
o [0]
porque no genera una excepción si el conjunto de consultas está vacío. Por lo tanto, no es necesario verificar usandoexists()