я пытаюсь сделать следующее:
получить 30 авторов с наивысшим баллом (
Author.objects.order_by('-score')[:30]
)упорядочить авторов по
last_name
Какие-либо предложения?
я пытаюсь сделать следующее:
получить 30 авторов с наивысшим баллом ( Author.objects.order_by('-score')[:30]
)
упорядочить авторов по last_name
Какие-либо предложения?
Ответы:
Что о
import operator
auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
В Django 1.4 и новее вы можете заказать, указав несколько полей.
Ссылка: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
order_by (* поля)
По умолчанию результаты, возвращаемые a QuerySet
, упорядочиваются по порядку кортежа, заданному ordering
параметром в мета-модели модели. Вы можете переопределить это для каждого QuerySet с помощью order_by
метода.
Пример:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Результат выше будет упорядочен по score
убыванию, а затем по last_name
возрастанию. Знак минус перед знаком "-score"
указывает на порядок убывания. Подразумевается порядок возрастания.
lambda x: x.last_name
? Он короче, многословен и не требует импорта.
Я просто хотел проиллюстрировать, что встроенные решения (только SQL) не всегда самые лучшие. Сначала я подумал, что, поскольку QuerySet.objects.order_by
метод Django принимает несколько аргументов, вы можете легко связать их:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Но это не работает так, как вы ожидаете. Показательный пример: сначала список президентов, отсортированный по количеству очков (для облегчения чтения выбрано 5 лучших):
>>> 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)
Используя решение Алекса Мартелли, которое точно определяет 5 лучших людей, отсортированных по 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)
А теперь комбинированный order_by
звонок:
>>> 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)
Как видите, это тот же результат, что и первый, а это означает, что он работает не так, как вы ожидали.
Вот способ, который учитывает ничью по отсеченному счету.
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')
Таким образом вы можете получить в top_authors более 30 авторов, и это возможно, min(30,author_count)
если у вас меньше 30 авторов.