web-dev-qa-db-fra.com

Bonnes façons de trier un queryset? - Django

ce que j'essaie de faire est la suivante:

  • obtenir les 30 auteurs avec le score le plus élevé (Author.objects.order_by('-score')[:30])

  • ordonner aux auteurs par last_name


Aucune suggestion?

98
RadiantHex

Qu'en est-il de

import operator

auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))

Dans Django 1.4 et plus récent, vous pouvez commander en fournissant plusieurs champs.
Référence: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

order_by (* champs)

Par défaut, les résultats renvoyés par un QuerySet sont classés par le tuple de classement donné par l’option ordering dans la méta du modèle. Vous pouvez remplacer ceci sur une base individuelle de QuerySet à l'aide de la commande order_by méthode.

Exemple:

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

Le résultat ci-dessus sera ordonné par score décroissant, puis par last_name Ascendant. Le signe négatif devant "-score" indique un ordre décroissant. L'ordre croissant est impliqué.

173
Alex Martelli

Je voulais simplement illustrer le fait que les solutions intégrées (SQL uniquement) ne sont pas toujours les meilleures. Au début, je pensais que parce que Django's QuerySet.objects.order_by La méthode accepte plusieurs arguments, vous pouvez facilement les chaîner:

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

Mais cela ne fonctionne pas comme prévu. Un exemple typique est une liste de présidents triés par score (en sélectionnant les 5 meilleurs pour en faciliter la lecture):

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

En utilisant la solution d'Alex Martelli qui fournit avec précision les 5 meilleures personnes triées par 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)

Et maintenant, le combiné order_by appel:

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

Comme vous pouvez le constater, le résultat est identique à celui du premier résultat, ce qui signifie que cela ne fonctionne pas comme prévu.

11
jathanism

Voici un moyen qui permet d’être à égalité pour le score de coupure.

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

De cette façon, vous pouvez obtenir plus de 30 auteurs dans top_authors et la min(30,author_count) existe si vous avez moins de 30 auteurs.

5
istruble