Gute Möglichkeiten, ein Abfrageset zu sortieren? - Django

111

Ich versuche Folgendes zu tun:

  • Holen Sie sich die 30 Autoren mit der höchsten Punktzahl ( Author.objects.order_by('-score')[:30])

  • Bestellen Sie die Autoren von last_name


Irgendwelche Vorschläge?

RadiantHex
quelle
4
@RH: Wie wäre es also, wenn Sie die Antwort von AlexMartelli als die richtige Lösung überprüfen? (nicht, dass er mehr Wiederholungen braucht, es sei denn, er geht diesem Skeet-Typen nach ...)
PaulMcG

Antworten:

190

Wie wäre es mit

import operator

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

In Django 1.4 und höher können Sie bestellen, indem Sie mehrere Felder angeben.
Referenz: https://docs.djangoproject.com/de/dev/ref/models/querysets/#order-by

order_by (* Felder)

Standardmäßig werden die von a zurückgegebenen Ergebnisse nach QuerySetdem Bestelltupel sortiert, das durch die orderingOption in der Meta des Modells angegeben wird. Sie können dies mit der order_byMethode pro QuerySet überschreiben .

Beispiel:

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

Das obige Ergebnis wird nach scoreabsteigend und dann nach last_nameaufsteigend geordnet . Das negative Vorzeichen vor "-score"zeigt die absteigende Reihenfolge an. Aufsteigende Reihenfolge ist impliziert.

Alex Martelli
quelle
1
@ Alex: grazie alex! Das war großartig, ich mache mich auf den Weg, um über das Bedienermodul zu lesen!
RadiantHex
3
Ist dies effizienter als Author.objects.order_by ('- score', 'last_name') [: 30]?
Brian Luft
4
@Brian - wenn mit "effizienter" "korrekter" gemeint ist, dann ja, es ist. :) Ihre Lösung hält die Autoren so gut wie nach Punktzahl sortiert und alphabetisiert nur die Autoren mit derselben Punktzahl (so funktionieren Sekundärschlüssel). Alex zeigt, wie man die Ergebnisse nimmt und dann eine völlig andere Sortierreihenfolge auf sie anwendet (indem key = operator.attrgetter verwendet wird, um einen Schlüsselausdruck pro Objekt zu definieren), wonach das OP gefragt hat.
PaulMcG
@Paul: das habe ich aber nicht gefragt, Alex 'Antwort ist die richtige!
RadiantHex
4
Warum nicht die Sortiertaste funktionsfähig machen lambda x: x.last_name? Es ist kürzer, ausführlicher und benötigt keinen Import.
Krzysztof Szularz
12

Ich wollte nur veranschaulichen, dass die integrierten Lösungen (nur SQL) nicht immer die besten sind. Zuerst dachte ich, da Djangos QuerySet.objects.order_byMethode mehrere Argumente akzeptiert, könnte man sie leicht verketten:

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

Aber es funktioniert nicht wie erwartet. Beispiel: Zunächst wird eine Liste der Präsidenten nach Punktzahl sortiert (Auswahl der Top 5 zum leichteren Lesen):

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

Verwenden der Lösung von Alex Martelli, die genau die fünf besten Personen liefert, sortiert nach 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)

Und jetzt der kombinierte order_byAnruf:

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

Wie Sie sehen, ist es das gleiche Ergebnis wie das erste, was bedeutet, dass es nicht wie erwartet funktioniert.

Nathanismus
quelle
13
Ihr Ergebnis Nr. 3 sortiert absteigend nach Punktzahl und dann nach Nachname IFF. Alle Objekte haben dieselbe Punktzahl. Das Problem ist, dass keines der Objekte in Ihrer Ergebnismenge dieselbe Punktzahl hat, sodass nur die '-Bewertung' die Sortierreihenfolge beeinflusst. Versuchen Sie, 3 Autoren auf 487 zu setzen, und führen Sie # 3 erneut aus.
Istruble
Ja, das verstehe ich. Ich wollte wirklich nur veranschaulichen, dass die integrierten Lösungen (nur SQL) nicht immer die besten sind.
Nathanismus
3
Es hat genau das getan, was ich erwartet hatte: lexikografische Reihenfolge (was ein bisschen trivial ist, wenn der erste Sortierschlüssel alle verschieden ist).
Jonas Kölker
5

Hier ist ein Weg, der Unentschieden für den Cut-Off-Score ermöglicht.

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

Auf diese Weise erhalten Sie möglicherweise mehr als 30 Autoren in top_authors, min(30,author_count)falls Sie weniger als 30 Autoren haben.

istruble
quelle