Хорошие способы сортировать набор запросов? - Джанго - PullRequest
90 голосов
/ 10 марта 2010

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

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

  • заказ авторов last_name


Есть предложения?

Ответы [ 3 ]

159 голосов
/ 10 марта 2010

А как же

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 (* поля)

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

Пример:

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

Результат выше будет упорядочен по убыванию score, затем по возрастанию last_name. Знак минус перед "-score" указывает на нисходящий порядок. В порядке возрастания подразумевается.

11 голосов
/ 10 марта 2010

Я просто хотел показать, что встроенные решения (только для 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)

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

5 голосов
/ 10 марта 2010

Вот способ, который учитывает связи для порогового значения.

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, и min(30,author_count) будет, если у вас менее 30 авторов.

...