首页 > 解决方案 > 根据同一模型上的子查询产生的行数更新 Django 模型

问题描述

我有一个 PostgreSQLUPDATE查询,它更新表中每一行的字段 ( global_ranking),基于ROW_NUMBER()同一个表中的每一行按另一个字段 ( rating) 排序。此外,更新是分区的,因此每行的排名仅与属于相同的那些行相关language

简而言之,我正在根据他们当前的评分更新游戏中每个玩家的排名。

PostgreSQL 查询如下所示:

UPDATE stats_userstats
SET    
    global_ranking = sub.row_number
FROM  (
    SELECT id, ROW_NUMBER() OVER (
        PARTITION BY language
        ORDER BY rating DESC
    ) AS row_number
    FROM stats_userstats
) sub
WHERE stats_userstats.id = sub.id;

我也在使用 Django,如果可能的话,学习如何使用 Django ORM 来表达这个查询会很有趣。

起初,Django 似乎拥有表达查询所需的一切,包括使用 PostgreSQL 的ROW_NUMBER()窗口函数的能力,但我最好的尝试更新所有ranking1

from django.db.models import F, OuterRef, Subquery
from django.db.models.expressions import Window
from django.db.models.functions import RowNumber

UserStats.objects.update(
    global_ranking=Subquery(
        UserStats.objects.filter(
            id=OuterRef('id')
        ).annotate(
            row_number=Window(
                expression=RowNumber(),
                partition_by=[F('language')],
                order_by=F('rating').desc()
            )
        ).values('row_number')
    )
)

我曾经from django.db import connection; print(connection.queries)看到那个 Django ORM 语句产生的查询,得到了这个模糊相似的 SQL 语句:

UPDATE "stats_userstats" 
SET "global_ranking" = (
    SELECT ROW_NUMBER() OVER (
        PARTITION BY U0."language"
        ORDER BY U0."rating" DESC
    ) AS "row_number" 
FROM "stats_userstats" U0 
WHERE U0."id" = "stats_userstats"."id"

看起来我需要做的是将子查询从SET查询​​部分移动到FROM,但我不清楚如何重组 Django ORM 语句来实现这一点。

任何帮助是极大的赞赏。谢谢!

标签: pythondjangopostgresqldjango-modelsdjango-orm

解决方案


推荐阅读