13

私は、データベース内のオブジェクトのスコアに関連するランクを見つけるための効率的な方法を見つけようとしています。私の素朴な解決策は次のようになります。

rank = 0
for q in Model.objects.all().order_by('score'):
  if q.name == 'searching_for_this'
    return rank
  rank += 1

order_byを使用して、データベースにフィルタリングを実行させることができるはずです。

Model.objects.all()。order_by('score')。filter(name ='searching_for_this')

しかし、フィルターの後のorder_byステップのインデックスを取得する方法はないようです。

これを行うためのより良い方法はありますか?(python / djangoおよび/またはrawSQLを使用します。)

私の次の考えは、挿入時にランクを事前に計算することですが、それは厄介なようです。

4

4 に答える 4

17

DjangoORMを使用して1つのデータベースクエリでこれを行うことはできないと思います。ただし、気にならない場合は、モデルにカスタムメソッドを作成します。

from django.db.models import Count

class Model(models.Model):
    score = models.IntegerField()
    ...

    def ranking(self):
        count = Model.objects.filter(score__lt=self.score).count()
        return count + 1

その後、通常のフィールドであるかのように、どこでも「ランキング」を使用できます。

print Model.objects.get(pk=1).ranking

編集:この回答は2010年のものです。最近は、代わりにカールのソリューションをお勧めします。

于 2010-04-17T17:24:00.927 に答える
13

Django 2.0の新しいウィンドウ関数を使用すると、次のように記述できます...

from django.db.models import Sum, F
from django.db.models.expressions import Window
from django.db.models.functions import Rank

Model.objects.filter(name='searching_for_this').annotate(
            rank=Window(
                expression=Rank(),
                order_by=F('score').desc()
            ),
        )
于 2018-07-13T03:33:18.767 に答える
3

次のようなものを使用します。

obj = Model.objects.get(name='searching_for_this')
rank = Model.objects.filter(score__gt=obj.score).count()

ランクが頻繁に使用され、パフォーマンスに影響を与える場合は、ランクを事前に計算してモデルに保存できます。

于 2010-04-17T17:20:48.173 に答える
2

標準準拠のデータベースエンジン(PostgreSql、SQL Server、Oracle、DB2など)を使用する「rawSQL」では、SQL標準RANK関数を使用できますが、一般的ではあるが非標準のエンジンではサポートされていません。 MySqlおよびSqliteとして、そして(おそらくそのために)Djangoはこの機能をアプリケーションに「表面化」しません。

于 2010-04-17T17:20:39.167 に答える