You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中使用窗口函数获取特定用户的正确排名

如何在Django中使用窗口函数获取特定用户的正确排名

我明白你的问题啦!你之前的写法之所以得到rank=1,是因为窗口函数的计算范围被提前过滤后的数据集限制了——当你先filter特定用户,窗口函数只能看到这一条数据,自然rank就是1。下面给你两种正确的解决思路:

方法一:先计算全局排名,再筛选特定用户(推荐)

这是最符合Django ORM最佳实践的方式,先对所有符合条件的用户计算全局排名,再过滤出目标用户的记录,这样得到的rank就是正确的全局排名:

from django.db.models import Window, DenseRank, F

# 先计算所有符合条件的钱包记录的全局排名,再筛选目标用户
user_rank = Wallet.objects.filter(type=0, space_id=space.id) \
    .annotate(
        rank=Window(
            expression=DenseRank(),
            order_by=F('point_amount').desc()
            # 这里不需要partition_by,因为我们要的是全局排名
        )
    ) \
    .filter(user_id=user.id) \
    .values("user__id", "user__username", "rank") \
    .first()

这个逻辑很清晰:先给所有type=0且属于目标space的Wallet记录计算出正确的DenseRank,之后再从中挑出你要的用户,这样拿到的rank就是该用户在全局中的真实排名。

方法二:对应你原生SQL的ORM写法

如果你想实现和你给出的原生SQL逻辑一致的ORM查询,可以用Subquery和StringAgg来模拟GROUP_CONCAT,再调用FIND_IN_SET函数:

from django.db.models import Subquery, StringAgg, F, Func

# 先构建子查询,获取按point_amount降序拼接的字符串
ranked_points_subquery = Wallet.objects.filter(type=0, space_id=space.id) \
    .order_by('-point_amount') \
    .annotate(ranked_points=StringAgg(F('point_amount'), delimiter=',')) \
    .values('ranked_points')

# 再查询目标用户,用FIND_IN_SET计算排名
user_rank = Wallet.objects.filter(type=0, space_id=space.id, user_id=user.id) \
    .annotate(
        ranked_points=Subquery(ranked_points_subquery)
    ) \
    .annotate(
        rank=Func(F('point_amount'), F('ranked_points'), function='FIND_IN_SET')
    ) \
    .values("user__id", "user__username", "rank") \
    .first()

不过这种写法相对复杂,不如第一种窗口函数的方式直观,所以更推荐第一种方法。

备注:内容来源于stack exchange,提问作者Farzam Pil Aghaee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 11:49:32