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?

78
demandé sur Ned Batchelder 2010-03-10 00:37:57

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.

140
répondu Alex Martelli 2015-09-21 13:45:16

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.

9
répondu jathanism 2010-03-10 17:53:30

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.

4
répondu istruble 2010-03-09 22:07:58