Хорошие способы отсортировать queryset? - Django

то, что я пытаюсь сделать, является этим:

  • получите эти 30 Авторов с самым высоким счетом ( Author.objects.order_by('-score')[:30] )

  • закажите авторам last_name


Какие-либо предложения?

99
задан Ned Batchelder 9 March 2010 в 23:24
поделиться

3 ответа

А как насчет

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 (* fields)

По умолчанию результаты, возвращаемые QuerySet , упорядочиваются по кортежу упорядочения, заданному опцией упорядочиванием в мета-модели модели. Вы можете переопределить это для каждого набора запросов с помощью метода order_by .

Пример:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

Результат выше будет отсортирован по баллам по убыванию, затем по last_name по возрастанию. Знак минус перед «- оценка» указывает на порядок убывания. Подразумевается возрастающий порядок.

175
ответ дан 24 November 2019 в 05:03
поделиться

Я просто хотел проиллюстрировать, что встроенные решения (только SQL) не всегда самые лучшие. Сначала я подумал, что, поскольку метод Django QuerySet.objects.order_by принимает несколько аргументов, вы можете легко объединить их в цепочку:

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)

Как видите, результат совпадает с первым, а это означает, что он работает не так, как вы ожидали.

11
ответ дан 24 November 2019 в 05:03
поделиться

Вот способ, который учитывает ничью по отсеченному счету.

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')

Таким образом вы можете получить более 30 авторов в top_authors и мин (30, author_count) там, если у вас меньше 30 авторов.

5
ответ дан 24 November 2019 в 05:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: