python - tupla - ¿La forma más rápida de obtener el primer objeto de un conjunto de consulta en django?
operaciones con diccionarios python (8)
A menudo me parece que quiero 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 eficiente.
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 ¿Esto es 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 muy intensiva en memoria cuando todo lo que realmente necesita es una prueba trivial.
¿Cómo puedo hacer esto con solo una llamada a la base de datos y sin agitar la memoria con objetos de excepción?
Ahora, en Django 1.9, tienes el método first()
para querysets.
YourModel.objects.all().first()
Esta es una mejor manera que .get()
o [0]
porque no arroja una excepción si el conjunto de consulta está vacío. Por lo tanto, no es necesario que compruebe el uso de exists()
Deberías usar los 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.
La respuesta correcta es
Entry.objects.all()[:1].get()
Que se puede usar 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. Simplemente haz lo anterior y solo extraerá el primero. Incluso podría usar .order_by
para asegurarse de obtener el primero que desea.
Asegúrese de agregar .get()
o de lo contrario obtendrá un QuerySet y no un objeto.
Puede ser así
obj = model.objects.filter(id=emp_id)[0]
o
obj = model.objects.latest(''id'')
Si planea obtener el primer elemento con frecuencia, 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)
Defina un modelo como este:
class MyModel(models.Model):
objects = ManagerWithFirstQuery()
Y úsalo así:
first_object = MyModel.objects.filter(x=100).first()
Django 1.6 (lanzado en noviembre de 2013) introdujo los docs.djangoproject.com/en/dev/ref/models/querysets/#first first()
y last()
que se tragan la excepción resultante y devuelven None
si el conjunto de consulta no devuelve ningún objeto.
r = list(qs[:1])
if r:
return r[0]
return None