lo que estoy tratando de hacer es esto:
consigue los 30 Autores con mayor puntuación (
Author.objects.order_by('-score')[:30]
)ordenar los autores por
last_name
¿Alguna sugerencia?
lo que estoy tratando de hacer es esto:
consigue los 30 Autores con mayor puntuación ( Author.objects.order_by('-score')[:30]
)
ordenar los autores por last_name
¿Alguna sugerencia?
Respuestas:
Qué pasa
import operator
auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
En Django 1.4 y versiones posteriores, puede ordenar proporcionando varios campos.
Referencia: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
order_by (* campos)
De forma predeterminada, los resultados devueltos por a QuerySet
están ordenados por la tupla de orden dada por la ordering
opción en el Meta del modelo. Puede anular esto por cada QuerySet mediante el order_by
método.
Ejemplo:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
El resultado anterior se ordenará score
descendiendo y luego last_name
ascendiendo. El signo negativo delante de "-score"
indica un orden descendente. El orden ascendente está implícito.
lambda x: x.last_name
? Es más corto, más detallado y no necesita ninguna importación.
Solo quería ilustrar que las soluciones integradas (solo SQL) no siempre son las mejores. Al principio pensé que debido a que el QuerySet.objects.order_by
método de Django acepta múltiples argumentos, podría encadenarlos fácilmente:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Pero no funciona como cabría esperar. Por ejemplo, primero hay una lista de presidentes ordenados por puntaje (seleccionando los 5 primeros para una lectura más fácil):
>>> auths = Author.objects.order_by('-score')[:5]
>>> for x in auths: print x
...
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)
Usando la solución de Alex Martelli que proporciona con precisión las 5 personas principales ordenadas por last_name
:
>>> for x in sorted(auths, key=operator.attrgetter('last_name')): print x
...
Benjamin Harrison (467)
James Monroe (487)
Gerald Rudolph (464)
Ulysses Simpson (474)
Harry Truman (471)
Y ahora la order_by
llamada combinada :
>>> myauths = Author.objects.order_by('-score', 'last_name')[:5]
>>> for x in myauths: print x
...
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)
Como puede ver, es el mismo resultado que el primero, lo que significa que no funciona como cabría esperar.
Aquí hay una forma que permite empates para el puntaje de corte.
author_count = Author.objects.count()
cut_off_score = Author.objects.order_by('-score').values_list('score')[min(30, author_count)]
top_authors = Author.objects.filter(score__gte=cut_off_score).order_by('last_name')
Puede obtener más de 30 autores en top_authors de esta manera y min(30,author_count)
existe el caso de que tenga menos de 30 autores.