如何在order_by之后获取结果在列表中的位置?

时间:2010-04-17 17:09:35

标签: python sql django rank

我正在尝试找到一种有效的方法来查找数据库中与其得分相关的对象的等级。我天真的解决方案看起来像这样:

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( '得分')。过滤器(名称= 'searching_for_this')

但似乎没有办法在过滤器后检索order_by步骤的索引。

有更好的方法吗? (使用python / django和/或原始SQL。)

我的下一个想法是在插入时预先计算排名,但这看起来很混乱。

4 个答案:

答案 0 :(得分:8)

我认为你不能在使用Django ORM的一个数据库查询中做到这一点。但如果它不困扰你,我会在模型上创建一个自定义方法:

from django.db.models import Count

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

    def ranking(self):
        aggregate = Model.objects.filter(score__lt=self.score).aggregate(ranking=Count('score'))
        return aggregate['ranking'] + 1

然后您可以在任何地方使用“排名”,就好像它是一个普通字段:

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

答案 1 :(得分:2)

在具有符合标准的数据库引擎(PostgreSql,SQL Server,Oracle,DB2,...)的“原始SQL”中,您可以使用SQL标准RANK函数 - 但不支持在流行但非标准的引擎中,例如MySql和Sqlite,以及(也许正因为如此)Django没有将此功能“表现”给应用程序。

答案 2 :(得分:1)

使用类似的东西:

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

如果频繁使用并影响性能,您可以预先计算排名并将其保存到模型中。

答案 3 :(得分:1)

使用new Window functions in 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()
            ),
        )