本文目录导读:

是的,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()
)
)
注意事项
-
数据库兼容性:窗口函数依赖于数据库支持,不同数据库的兼容性:
- PostgreSQL:全面支持
- MySQL 8.0+:大多数支持
- SQLite 3.25+:基本支持
- Oracle:全面支持
-
框架限制:窗口函数的
frame目前只支持ROWS模式,不支持RANGE或GROUPS -
性能考虑:窗口函数可能对数据库性能有影响,建议在大数据集上使用时注意优化
替代方案(如果数据库不支持)
# 使用子查询模拟窗口函数
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的窗口函数功能已经相当完善,可以满足大多数分析查询需求,如果你的数据库版本支持,推荐直接使用原生的窗口函数,性能更好,代码也更简洁。