¿La forma más rápida de obtener el primer objeto de un queryset en django?

A menudo me encuentro con ganas de obtener el primer objeto de un queryset en Django, o devolver None si no hay ninguno. Hay muchas formas de hacer esto que funcionan. Pero me pregunto cuál es el más performante.

 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 if trivial.

¿Cómo puedo hacer esto con una sola llamada a la base de datos y sin batir la memoria con objetos de excepción?

Django 1.6 (publicado en noviembre de 2013) introdujo los métodos de conveniencia first() y last() que tragan la excepción resultante y devuelven None si el queryset no devuelve ningún objeto.

La respuesta correcta es

 Entry.objects.all()[:1].get() 

Que se puede utilizar en:

 Entry.objects.filter()[:1].get() 

No querría convertirlo primero en una lista porque eso forzaría una llamada a la base de datos completa de todos los registros. Solo haz lo de arriba y solo tirará de lo primero. Incluso .order_by usar .order_by para asegurarte de obtener lo primero que deseas.

Asegúrese de agregar el .get() o de lo contrario obtendrá un QuerySet de vuelta y no un objeto.

 r = list(qs[:1]) if r: return r[0] return None 

Ahora, en Django 1.9 tienes el first() método first() para querysets.

 YourModel.objects.all().first() 

Esta es una forma mejor que .get() o [0] porque no lanza una excepción si queryset está vacío, por lo tanto, no es necesario verificar que exists() utilizando exists()

Si planea obtener el primer elemento a menudo, puede extender QuerySet en esta dirección:

 class FirstQuerySet(models.query.QuerySet): def first(self): return self[0] class ManagerWithFirstQuery(models.Manager): def get_query_set(self): return FirstQuerySet(self.model) 

Definir modelo como este:

 class MyModel(models.Model): objects = ManagerWithFirstQuery() 

Y úsalo así:

  first_object = MyModel.objects.filter(x=100).first() 

Puede ser asi

 obj = model.objects.filter(id=emp_id)[0] 

o

 obj = model.objects.latest('id') 

Deberías usar métodos django, como existe. Está ahí para que lo uses.

 if qs.exists(): return qs[0] return None 

Esto podría funcionar también:

 def get_first_element(MyModel): my_query = MyModel.objects.all() return my_query[:1] 

si está vacío, devuelve una lista vacía, de lo contrario devuelve el primer elemento dentro de una lista.