co próbuję zrobić to:
zdobądź 30 autorów z najwyższym wynikiem (
Author.objects.order_by('-score')[:30]
)zamów autorów wg
last_name
Jakieś sugestie?
co próbuję zrobić to:
zdobądź 30 autorów z najwyższym wynikiem ( Author.objects.order_by('-score')[:30]
)
zamów autorów wg last_name
Jakieś sugestie?
Odpowiedzi:
Co powiesz na
import operator
auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
W Django 1.4 i nowszych można składać zamówienia, udostępniając wiele pól.
Źródła: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
order_by (* pola)
Domyślnie wyniki zwracane przez a QuerySet
są uporządkowane według krotki porządkowania podanej przez ordering
opcję w Meta modelu. Możesz to zmienić na podstawie QuerySet przy użyciu order_by
metody.
Przykład:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Powyższy wynik zostanie uporządkowany score
malejąco, a następnie last_name
rosnąco. Znak minus przed "-score"
oznacza malejącą kolejność. Domniemany jest porządek rosnący.
lambda x: x.last_name
? Jest krótszy, bardziej szczegółowy i nie wymaga importu.
Chciałem tylko zilustrować, że wbudowane rozwiązania (tylko SQL) nie zawsze są najlepsze. Na początku pomyślałem, że QuerySet.objects.order_by
skoro metoda Django przyjmuje wiele argumentów, możesz łatwo połączyć je w łańcuch:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Ale to nie działa tak, jak można by się tego spodziewać. Przykładowo, pierwsza to lista prezydentów posortowana według punktacji (wybranie 5 najlepszych dla łatwiejszego czytania):
>>> 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)
Korzystając z rozwiązania Alexa Martelli, które dokładnie przedstawia 5 najlepszych osób posortowanych według 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)
A teraz połączone order_by
połączenie:
>>> 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)
Jak widać, jest to ten sam wynik, co pierwszy, co oznacza, że nie działa zgodnie z oczekiwaniami.
Oto sposób, który pozwala na remisy dla końcowego wyniku.
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')
W ten sposób możesz znaleźć więcej niż 30 autorów w top_authors, a min(30,author_count)
jeśli masz mniej niż 30 autorów.