De bonnes façons de trier un queryset? - Django
Ce que j'essaie de faire est ceci:
Obtenez les 30 Auteurs avec la note la plus élevée (
Author.objects.order_by('-score')[:30]
)Les auteurs par Ordre
last_name
Des suggestions?
3 réponses
Et
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 triés par le tuple de commande donné par l'option ordering
dans la méta du modèle. Vous pouvez remplacer ceci sur une base par jeu de requêtes en utilisant order_by
méthode.
Exemple:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Le résultat ci-dessus seront commandés par score
décroissant, puis par last_name
croissant. Le signe négatif devant "-score"
indique l'ordre décroissant. L'ordre croissant est implicite.
Je voulais juste illustrer que les solutions intégrées (SQL uniquement) ne sont pas toujours les meilleures. Au début, je pensais que parce que la méthode QuerySet.objects.order_by
de Django accepte plusieurs arguments, vous pourriez facilement les enchaîner:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Mais, cela ne fonctionne pas comme on pouvait s'y attendre. Par exemple, la première est une liste des Présidents triés par score (Sélection top 5 pour 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 le Top 5 des 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 l'appel order_by
combiné:
>>> 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 voir, c'est le même résultat que le premier, ce qui signifie que cela ne fonctionne pas comme prévu.
Voici un moyen qui permet des liens 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')
Vous pouvez obtenir plus de 30 auteurs dans top_authors de cette façon et le min(30,author_count)
est là dans le cas où vous avez moins de 30 auteurs.