クエリセットを並べ替える良い方法は?-Django


111

私がやろうとしているのはこれです:

  • 最高スコアの著者30人を取得(Author.objects.order_by('-score')[:30]

  • 著者を注文する last_name


助言がありますか?


4
@RH:では、正しい解決策としてAlexMartelliの答えを確認するのはどうですか?(彼がそのスキートの男を追っていない限り、彼はこれ以上の担当者を必要とするわけではない...)
PaulMcG

回答:


190

どうですか

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(* fields)

デフォルトでは、によって返される結果は、モデルのメタのオプションでQuerySet指定された順序付けタプルによって順序付けされorderingます。order_byメソッドを使用して、QuerySetごとにこれをオーバーライドできます。

例:

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

上記の結果は、score降順、次にlast_name昇順で並べ替えられます。の前の負符号"-score"は降順を示します。昇順を意味します。


1
@アレックス:グラジーアレックス!それは素晴らしかった、私はオペレーターモジュールについて読むことになっています!
RadiantHex 2009年

3
これはAuthor.objects.order_by( '-score'、 'last_name')[:30]よりも効率的ですか?
Brian Luft

4
@ブライアン-「より効率的」とは、「より正確」を意味するのであれば、そうです。:)あなたのソリューションは、著者をスコアでかなりソートし、同じスコアを持つ著者のみをアルファベット順に並べます(これは二次キーがどのように機能するかです)。Alexは結果を取得する方法を示し、OPが要求したとおりに、完全に異なる並べ替え順序をそれらに適用します(key = operator.attrgetterを使用してオブジェクトごとのキー式を定義します)。
PaulMcG 2010年

@ポール:それは私が尋ねたものではありません、アレックスの答えは正しいです!
RadiantHex 2010年

4
ソートキー機能を作ってみませんlambda x: x.last_nameか?より短く、より冗長で、インポートを必要としません。
Krzysztof Szularz 2013

12

組み込みのソリューション(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人を正確に提供するAlex Martelliのソリューションを使用します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)

ご覧のとおり、最初の結果と同じ結果です。つまり、期待どおりに機能しません。


13
結果#3はスコアで降順にソートされ、last_name IFFですべてのオブジェクトが同じスコアになります。問題は、結果セット内のどのオブジェクトも同じスコアを持たないため、 '-score'のみがソート順に影響していることです。3人の著者のスコアを487に設定して、#3をもう一度実行してください。
istruble

そうだね。私は本当に組み込みのソリューション(SQLのみ)が常に最良のものではないことを説明したかっただけです。
ジェサニズム

3
それは、私が期待したとおりに行われました。辞書式順序付け(最初のソート・キーがすべて異なる場合、それはちょっと自明です)。
JonasKölker12年

5

これは、カットオフスコアの同点を可能にする方法です。

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

この方法では、top_authorsで30人以上の著者を取得min(30,author_count)できますが、30人未満の著者がいる場合は、そこにあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.