Django ORM:带后续过滤的窗口函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django ORM:带后续过滤的窗口函数相关的知识,希望对你有一定的参考价值。

回答 这个问题, I 发现 窗口函数不允许与过滤器结合(技术上是允许的,但过滤器子句会影响窗口)。有一个提示,就是要把window函数包在一个内部查询中,所以最后的SQL是这样的(据我了解)。

SELECT * FROM (
    SELECT *, *window_function* FROM TABLE)
WHERE *filtering_conditions*

问题是:如何用Django ORM写这个查询?

答案

另一种解决方案是通用表表达式(CTE),借助于 django-cte,你可以实现你想要的东西。

cte = With(
    YouModel.objects.annotate(
        your_window_function=Window(...),
    )
)

qs = cte.queryset().with_cte(cte).filter(your_window_function='something')

大致意思是:

WITH cte as (
    SELECT *, WINDOW(...) as your_window_function
    FROM yourmodel
) 
SELECT * 
FROM cte
WHERE cte.your_window_function = 'something'
另一答案

有开发者有兴趣解决这个问题 但现在的ORM还不可能做到这一点。

一个建议的解决方案是在系统中添加一个 QuerySet.subquery().wrap() 的方法 推送 子查询中的查询集,这样就可以对其进行过滤。

另一答案

你需要使用原始查询。为了在一个查询中进行多个查询。django文档

for p in Person.objects.raw('''
    SELECT * FROM (SELECT *, *window_function* FROM TABLE)
    WHERE *filtering_conditions*'''):
    print(p)
# John Smith
# Jane Jones

你可以做的其他事情是以下。

模型.py

class Category(models.Model):
    name = models.CharField(max_length=100)


class Hero(models.Model):
    # ...
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

    benevolence_factor = models.PositiveSmallIntegerField(
        help_text="How benevolent this hero is?",
        default=50
    )

querySet.py

hero_qs = Hero.objects.filter(category=OuterRef("pk"))
.order_by("-benevolence_factor")

Category.objects.all()
.annotate(most_benevolent_hero=Subquery(hero_qs.values('name')[:1]))

生成的SQL看起来像这样...

SELECT "entities_category"."id",
   "entities_category"."name",

  (SELECT U0."name"
   FROM "entities_hero" U0
   WHERE U0."category_id" = ("entities_category"."id")
   ORDER BY U0."benevolence_factor" DESC
   LIMIT 1) AS "most_benevolent_hero"
FROM "entities_category"

以上是关于Django ORM:带后续过滤的窗口函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 ORM Django 过滤新更新的查询集返回空查询集

在 django ORM 中使用 postgresql 窗口函数的干净方法?

Django ORM group by,并找到每个组的最新项目(窗口函数)

django ORM:shell和应用程序之间的过滤结果不同

Django ORM:按对象列表过滤

Django ORM数据库查询操作