如何为后续的Django查询添加全局排名注释?

问题描述 投票:0回答:1

我有一个 Django 模型,如下所示:

class LeaderboardScore(models.Model):
  score = models.FloatField()
  player_account = models.ForeignKey(PlayerAccount, on_delete=models.CASCADE)
  timestamp = models.DateTimeField()

这代表游戏中的最高分。分数按照分数降序和时间戳升序排列,因此如果两个分数相同,则最早的分数排名更高。

每次查询排行榜时,我都希望在查询结果中包含每个实例的全球排名。当我像这样查询所有分数时,我可以成功做到这一点:

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

lq = LeaderboardScore.objects.filter(leaderboard__id=1).annotate(
  rank=Window(
    expression=DenseRank(),
    order_by=[F('score').desc(), F('timestamp').asc()]
  )
)

这将在排名字段中正确显示排名。但是如果我接受上面的查询并按player_account过滤它,如下所示:

# rank will be 1, but should be the global ranking
lq.filter(player_account__id=123)[0].rank

然后重置排名,以便查询中的第一个项目的排名为 1,即使其全局排名应该不同。如何保持全球排名?

django orm
1个回答
0
投票

我不知道如何执行 Django 的 ORM,但我能够使用 SQL 作为临时解决方案:

WITH ranked_leaderboard AS (
  SELECT
    id,
    score,
    timestamp,
    player_account_id,
    DENSE_RANK() OVER (ORDER BY score DESC, timestamp ASC) AS rank
  FROM
    leaderboards_leaderboardscore
  WHERE
    leaderboard_id = 1
)
SELECT
  id,
  score,
  timestamp,
  rank
FROM
  ranked_leaderboard
WHERE
  player_account_id = 123
ORDER BY
  score DESC, timestamp ASC

这不是一个理想的解决方案,因为它仅在我搜索特定玩家时才有效 - 我还有其他查询可能由任意玩家列表组成,我对此使用了非最佳解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.