o que estou tentando fazer é o seguinte:
obtenha os 30 autores com maior pontuação (
Author.objects.order_by('-score')[:30]
)ordenar os autores por
last_name
Alguma sugestão?
o que estou tentando fazer é o seguinte:
obtenha os 30 autores com maior pontuação ( Author.objects.order_by('-score')[:30]
)
ordenar os autores por last_name
Alguma sugestão?
Respostas:
A respeito
import operator
auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
No Django 1.4 e mais recente, você pode fazer o pedido fornecendo vários campos.
Referência: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
order_by (* campos)
Por padrão, os resultados retornados por a QuerySet
são ordenados pela tupla de ordenação fornecida pela ordering
opção no Meta do modelo. Você pode substituir isso por QuerySet usando o order_by
método.
Exemplo:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
O resultado acima será ordenado em ordem score
decrescente e depois em ordem last_name
crescente. O sinal negativo na frente de "-score"
indica ordem decrescente. A ordem crescente está implícita.
lambda x: x.last_name
? É mais curto, mais detalhado e não precisa de nenhuma importação.
Eu só queria ilustrar que as soluções integradas (somente SQL) nem sempre são as melhores. A princípio pensei que, como o QuerySet.objects.order_by
método do Django aceita vários argumentos, você poderia facilmente encadea-los:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Mas não funciona como você esperaria. Caso em questão, primeiro está uma lista de presidentes classificados por pontuação (selecionando os 5 primeiros para facilitar a leitura):
>>> 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 a solução de Alex Martelli, que fornece com precisão as 5 principais pessoas classificadas 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)
E agora a order_by
chamada 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 você pode ver, é o mesmo resultado do primeiro, o que significa que não funciona como você esperava.
Esta é uma maneira que permite empates para a pontuação 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')
Você pode obter mais de 30 autores em top_authors dessa forma e min(30,author_count)
há no caso de você ter menos de 30 autores.