我需要将PostgreSQL的rank()窗口函数应用于来自Django的ORM的带注释的查询集。 Django的sql查询必须是子查询才能应用窗口函数,这就是我到目前为止所做的:
queryset = Item.objects.annotate(…)
queryset_with_rank = Items.objects.raw("""
select rank() over (order by points), *
from (%(subquery)s)""", { 'subquery': queryset.query }
)
不幸的是,queryset.query
返回的查询没有正确引用用于注释的参数,尽管查询本身执行得非常好。
queryset_with_rank.query
或queryset.query
返回的查询返回以下内容
"participation"."category" = )
"participation"."category" = amateur)
我更期待
"participation"."category" = '')
"participation"."category" = 'amateur')
我注意到Django文档说明了以下关于Query.__str__()
参数值不一定必须正确引用,因为这是在执行时由数据库接口完成的。
只要我手动修复报价并自己将其传递给Postgres,一切都按预期工作。有没有办法通过正确的引用接收所需的子查询?或者是否有另一种更好的方法将窗口函数应用于Django ORM查询集althehe?
答案 0 :(得分:2)
作为Django核心开发人员Aymeric Augustin said,无法预先获得数据库后端执行的确切查询。
我仍然设法以我希望的方式构建查询,虽然有点麻烦:
# Obtain query and parameters separately
query, params = item_queryset.query.sql_with_params()
# Put additional quotes around string. I guess this is what
# the database adapter does as well.
params = [
'\'{}\''.format(p)
if isinstance(p, basestring) else p
for p in params
]
# Cast list of parameters to tuple because I got
# "not enough format characters" otherwise. Dunno why.
params = tuple(params)
participations = Item.objects.raw("""
select *,
rank() over (order by points DESC) as rank
from ({subquery}
""".format(subquery=query.format(params)), []
)