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

发布于 2024-08-29 10:00:24 字数 447 浏览 5 评论 0原文

我正在尝试找到一种有效的方法来查找数据库中对象与其分数相关的排名。我天真的解决方案如下所示:

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

但是没有' t 似乎是在过滤器之后检索 order_by 步骤索引的一种方法。

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

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

I'm trying to find an efficient way to find the rank of an object in the database related to it's score. My naive solution looks like this:

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

It should be possible to get the database to do the filtering, using order_by:

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

But there doesn't seem to be a way to retrieve the index for the order_by step after the filter.

Is there a better way to do this? (Using python/django and/or raw SQL.)

My next thought is to pre-compute ranks on insert but that seems messy.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

柠檬 2024-09-05 10:00:24

我认为您无法使用 Django ORM 在一个数据库查询中完成此操作。但如果它不打扰你,我会在模型上创建一个自定义方法:

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 年现在我会推荐卡尔的解决方案

I don't think you can do this in one database query using Django ORM. But if it doesn't bothers you, I would create a custom method on a model:

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

You can then use "ranking" anywhere, as if it was a normal field:

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

Edit: This answer is from 2010. Nowadays I would recommend Carl's solution instead.

谁对谁错谁最难过 2024-09-05 10:00:24

使用 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()
            ),
        )

Using the new Window functions in Django 2.0 you could write it like this...

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()
            ),
        )
ゃ懵逼小萝莉 2024-09-05 10:00:24

使用类似这样的内容:

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

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

Use something like this:

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

You can pre-compute ranks and save it to Model if they are frequently used and affect the performance.

魂ガ小子 2024-09-05 10:00:24

在具有符合标准的数据库引擎(PostgreSql、SQL Server、Oracle、DB2...)的“原始 SQL”中,您可以只使用 SQL 标准 RANK 函数 - 但这不受支持在流行但非标准的引擎中,例如 MySql 和 Sqlite,并且(也许正因为如此)Django 不会向应用程序“显示”此功能。

In "raw SQL" with a standard-conforming database engine (PostgreSql, SQL Server, Oracle, DB2, ...), you can just use the SQL-standard RANK function -- but that's not supported in popular but non-standard engines such as MySql and Sqlite, and (perhaps because of that) Django does not "surface" this functionality to the application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文