如何使用Django ORM获取任意时间段内的移动平均或最大值
使用Django ORM计算任意连续X天内食材最大订购量
可以实现,核心是借助窗口函数处理滑动窗口的求和逻辑,以下是具体实现方案:
前提准备
确保你的数据库支持窗口函数(如PostgreSQL、MySQL 8.0+、SQLite 3.25+),同时导入需要的ORM工具:
from django.db.models import Sum, Max, Window, F from django.db.models.functions import TruncDate from django.db.models.window import RangeFrame
实现步骤
1. 先聚合每日食材订购总量
如果同一天同一食材存在多条订购记录,先合并为单日总量,避免重复计算:
X = 7 # 自定义连续天数,可替换为任意正整数 start_date = # 你的筛选起始日期(如datetime.date(2024,1,1)) end_date = # 你的筛选结束日期(如datetime.date(2024,6,1)) daily_totals = Order.objects.filter( date__gte=start_date, date__lt=end_date ).annotate( day=TruncDate('date') # 统一日期格式,去掉时间部分(如果有的话) ).values('ingredient', 'day').annotate( daily_quantity=Sum('quantity') ).order_by('ingredient', 'day')
2. 滑动窗口求和并取最大值
通过Window函数定义滑动窗口范围,计算每个日期点往前X-1天的累计订购量,再提取每个食材的最大值:
max_window_totals = daily_totals.annotate( window_total=Window( expression=Sum('daily_quantity'), partition_by=F('ingredient'), # 按食材分组计算 order_by=F('day').asc(), # 按日期排序,保证窗口滑动顺序 frame=RangeFrame(start=-X+1, end=0) # 滑动窗口范围:当前日期往前X-1天到当天(共X天) ) ).values('ingredient').annotate( max_quantity=Max('window_total') ).order_by('ingredient')
关键说明
RangeFrame(start=-X+1, end=0):这里的数值是基于日期的相对偏移,比如X=7时,-6表示从当前日期往前推6天,加上当天正好是连续7天的窗口。- 最终
max_window_totals的结果是每个食材对应的最大连续X天订购量,格式为[{'ingredient': '番茄', 'max_quantity': 150}, ...]。
备选方案(针对不支持RangeFrame的数据库)
如果数据库不支持RangeFrame,可以用自连接实现,但效率较低,仅适合小数据量场景:
import datetime from django.db.models import Q max_totals = [] ingredients = Order.objects.filter(date__gte=start_date, date__lt=end_date).values_list('ingredient', flat=True).distinct() for ingredient in ingredients: # 遍历每个食材,计算所有可能的连续X天总和 window_sums = Order.objects.filter( ingredient=ingredient, date__gte=start_date, date__lt=end_date ).annotate( window_end=F('date') ).filter( Q(date__gte=F('window_end') - datetime.timedelta(days=X-1)) ).values('window_end').annotate( window_total=Sum('quantity') ).aggregate(max_total=Max('window_total')) max_totals.append({ 'ingredient': ingredient, 'max_quantity': window_sums['max_total'] or 0 })
内容的提问来源于stack exchange,提问作者David Downes
相关产品推荐
相关产品推荐

