Obtener el ultimo elemento de un queryset

2,020 views
Skip to first unread message

Eduard Diaz

unread,
Mar 26, 2012, 1:22:25 PM3/26/12
to djan...@googlegroups.com
Hola,

Me gustaria obtener de una forma sencilla y eficiente el ultimo elemento de una queryset, por ejemplo:

>>> from django.contrib.auth.models import User
>>> users = User.objects.all()
>>> first = users[0]
>>> last = users[-1]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/usuario/.virtualenvs/proyecto.com/local/lib/python2.7/site-packages/django/db/models/query.py", line 157, in __getitem__
    "Negative indexing is not supported."
AssertionError: Negative indexing is not supported.

Mi pregunta es si tenemos que el primer elemento de la queryset users es users[0], como puedo obtener el último si necesidad de hacer otra consulta a la base de datos?

Seguro que es una tonteria, pero... es que hoy estoy muy muy espeso

Gracias por adelatado

Uns saludo

Eduard

Miguel

unread,
Mar 26, 2012, 1:26:48 PM3/26/12
to djan...@googlegroups.com
users = User.objects.all()

longitud = users

print users[longitud-1]

Espero te sirva.



Eduard

--
Ha recibido este mensaje porque está suscrito a Grupo "Grupo de Usuarios del Framework Django de habla hispana" de Grupos de Google.
Si quieres publicar en este grupo, envía un mensaje de correo
electrónico a djan...@googlegroups.com
Para anular la suscripción a este grupo, envíe un mensaje a django-es-...@googlegroups.com
Para obtener más opciones, visita este grupo en http://groups.google.com.bo/group/django-es.



--
ISC. JMSM



Eduard Diaz

unread,
Mar 26, 2012, 1:48:28 PM3/26/12
to djan...@googlegroups.com
Hola Miguel,

Muchas gracias por responder

En la solución que propones supongo que te refieres a

longitud = len(users)

porque si no, la línea:

print users[longitud-1]

te dará un error TypeError ya que no se pueden restar una queryset y un numero entero

De todas maneras, creo que lo mejor es hecer un list(users) por ejemplo:


>>> from django.contrib.auth.models import User
>>> users = User.objects.all()
>>> lusers = list(users)
>>> first = lusers[0]
>>> last = lusers[-1]

Así el slicing funciona como siempre, aunque sospecho que tendrá una pega y por eso los de django no han implementado los indices negativos en el slicing, habrá que investigar...

Pero hoy me parece que con esto ya me conformo

Muchas gracias de nuevo!!

Saludos

Eduard

Miguel

unread,
Mar 26, 2012, 2:01:54 PM3/26/12
to djan...@googlegroups.com
Si tienes razon, se me paso obtener la longitud del objeto user

lo acabo de probar como te comente y me arrojo esto:

>>> from django.contrib.auth.models import User
>>> users = User.objects.all()
>>> lon = len(users)
>>> print users[0]
dummy
>>> print users[lon-1]
admin
>>> print lon
2
>>> 

Saludos

rikuth...@gmail.com

unread,
Mar 26, 2012, 4:20:23 PM3/26/12
to djan...@googlegroups.com
Funciona pero no es lo mejor. Los queryset tienen una función count() que internamente usa el COUNT de SQL, lo cual es mucho mas eficiente que hacer un len() de los objetos, ya que el len() lo que hará seguramente es convertir el queryset a lista (haciendo un GET por cada elemento) y luego contarlos. Es decir, n transacciones contra solo una.

La mejor solución sería:

>>> from django.contrib.auth.models import User
>>> users = User.objects.all()
>>> lon = users.count()  # o User.objects.count()
>>> print users[0]
dummy
>>> print users[lon-1]
admin
>>> print lon
2
Pablo Recio Quijano

Jesús Espino

unread,
Mar 27, 2012, 3:21:38 AM3/27/12
to djan...@googlegroups.com
Si fuera posible, aunque no se si para el problema que tienes es posible, lo ideal sería hacer ordenación inversa y obtener el primer resultado. Eso haría que solo ejecutaras una query SQL. Si necesitas acceder al primero y al ultimo y la lista de resultados es grande, la opcion del .count es la mas eficiente. Si necesitas acceder al primero y al ultimo y la lista es pequeña, no sería raro que el rendimiento de list(queryset) te de un mejor rendimiento, ya que usaría una unica query sql, y el resto se haría en memoria en la aplicación.

Un saludo.

Eduard Diaz

unread,
Mar 27, 2012, 5:50:51 AM3/27/12
to djan...@googlegroups.com
En resumen, tenemos 3 opciones:

A)  Solucion dos consultas a la base de datos, una con ordenación ascendente y otra con ordenación descendente. Obtener el primer resultado en ambos casos

B)  Solución con el count() en este caso también tendríamos 3 consultas la consulta inicial, otra para el count y una tercera para el getitem

C)  Solución list(queryset), buen rendimiento para listas pequeñas, se hace una consulta inicial y el resto en memoria de la aplicación

Según Jesús las podemos clasificar de la siguiente manera:

A) Es la solución ideal
B) La más eficiente con listas grandes
C) La de mejor rendimiento en listas pequeñas

Gracias a todos por las respuestas
Reply all
Reply to author
Forward
0 new messages