You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:50:17