未引用子查询/参数的等级的原始查询

时间:2016-08-19 10:05:23

标签: django django-orm

我的目标

我需要将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.queryqueryset.query返回的查询返回以下内容

"participation"."category" = )
"participation"."category" = amateur)

我更期待

"participation"."category" = '')
"participation"."category" = 'amateur')

问题

我注意到Django文档说明了以下关于Query.__str__()

的内容
  

参数值不一定必须正确引用,因为这是在执行时由数据库接口完成的。

只要我手动修复报价并自己将其传递给Postgres,一切都按预期工作。有没有办法通过正确的引用接收所需的子查询?或者是否有另一种更好的方法将窗口函数应用于Django ORM查询集althehe?

1 个答案:

答案 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)), []
)