Django窗口函数支持了吗

wen python案例 1

本文目录导读:

Django窗口函数支持了吗

  1. 版本支持情况
  2. 主要支持的窗口函数
  3. 实际使用示例
  4. 注意事项
  5. 替代方案(如果数据库不支持)

是的,Django ORM 从 Django 3.2 开始支持窗口函数,具体支持情况如下:

版本支持情况

  • Django 3.2+:支持基本的窗口函数功能
  • Django 4.0+:增加更多窗口函数和功能
  • Django 5.0+:进一步增强了窗口函数的能力

主要支持的窗口函数

排名函数

from django.db.models import Window
from django.db.models.functions import Rank, DenseRank, RowNumber, NTile
# 行号
MyModel.objects.annotate(
    row_num=Window(expression=RowNumber(), order_by='-created_at')
)
# 排名(允许并列,有间隙)
MyModel.objects.annotate(
    rank=Window(expression=Rank(), order_by='-score')
)
# 密集排名(允许并列,无间隙)
MyModel.objects.annotate(
    dense_rank=Window(expression=DenseRank(), order_by='-score')
)
# 分桶
MyModel.objects.annotate(
    ntile=Window(expression=NTile(4), order_by='-score')
)

偏移函数

from django.db.models.functions import Lag, Lead, FirstValue, LastValue
# 前一行
MyModel.objects.annotate(
    prev_score=Window(expression=Lag('score'), order_by='created_at')
)
# 后一行
MyModel.objects.annotate(
    next_score=Window(expression=Lead('score'), order_by='created_at')
)
# 第一个值
MyModel.objects.annotate(
    first=Window(expression=FirstValue('score'), 
                 partition_by='category', 
                 order_by='created_at')
)
# 最后一个值
MyModel.objects.annotate(
    last=Window(expression=LastValue('score'), 
                partition_by='category', 
                order_by='created_at')
)

聚合函数作为窗口函数

from django.db.models import Sum, Avg, Count, Max, Min
# 累计求和
MyModel.objects.annotate(
    running_total=Window(
        expression=Sum('amount'),
        order_by='created_at'
    )
)
# 分区平均值
MyModel.objects.annotate(
    category_avg=Window(
        expression=Avg('score'),
        partition_by='category'
    )
)
# 分区内的最大值
MyModel.objects.annotate(
    category_max=Window(
        expression=Max('score'),
        partition_by='category'
    )
)

实际使用示例

示例1:计算累计总和

from django.db.models import Window, F
from django.db.models.functions import Sum
# 按部门分组,计算员工薪资的累计和
Employee.objects.annotate(
    running_salary=Window(
        expression=Sum('salary'),
        partition_by=['department'],
        order_by=['hire_date']
    )
)

示例2:计算移动平均

from django.db.models import Window, Avg
from django.db.models.functions import RowNumber
# 3期移动平均
Sales.objects.annotate(
    moving_avg=Window(
        expression=Avg('amount'),
        order_by='date',
        frame=Window.ROWS(
            start=-2,  # 前2行
            end=0      # 当前行
        )
    )
)

示例3:分区计算排名

# 按部门分区,按薪资排名
Employee.objects.annotate(
    salary_rank=Window(
        expression=Rank(),
        partition_by=['department'],
        order_by=F('salary').desc()
    )
)

注意事项

  1. 数据库兼容性:窗口函数依赖于数据库支持,不同数据库的兼容性:

    • PostgreSQL:全面支持
    • MySQL 8.0+:大多数支持
    • SQLite 3.25+:基本支持
    • Oracle:全面支持
  2. 框架限制:窗口函数的 frame 目前只支持 ROWS 模式,不支持 RANGEGROUPS

  3. 性能考虑:窗口函数可能对数据库性能有影响,建议在大数据集上使用时注意优化

替代方案(如果数据库不支持)

# 使用子查询模拟窗口函数
from django.db.models import Subquery, OuterRef
rank_subquery = Employee.objects.filter(
    department=OuterRef('department'),
    salary__gte=OuterRef('salary')
).annotate(
    count=Count('id')
).values('count')[:1]
Employee.objects.annotate(
    salary_rank=Subquery(rank_subquery)
)

Django的窗口函数功能已经相当完善,可以满足大多数分析查询需求,如果你的数据库版本支持,推荐直接使用原生的窗口函数,性能更好,代码也更简洁。

抱歉,评论功能暂时关闭!