Django如何构造QuerySet实现按指定小时间隔筛选时间范围内的价格数据
Django自定义时间切片间隔获取价格数据实现方案
方案1:生成目标时间点直接匹配(推荐,逻辑简单不易出错)
这个方法直接在Python层计算出所有需要匹配的时间切片点,再传入ORM做筛选,兼容所有Django版本,无需额外数据库函数支持。
完整代码
from datetime import timedelta from django.utils import timezone def _get_prices_per_time_slice(self, last_hours=24, time_slice_in_hours=4): now = timezone.now() end_time = now.replace(second=0, microsecond=0) start_time = end_time - timedelta(hours=last_hours) # 生成所有需要匹配的时间切片点 target_time_points = [] current_time = end_time while current_time >= start_time: target_time_points.append(current_time) current_time -= timedelta(hours=time_slice_in_hours) qset = Price.objects.filter( created__in=target_time_points, created__minute=end_time.minute ).values('price') return [r['price'] for r in qset]
逻辑说明
- 从结束时间开始,每次减去
time_slice_in_hours小时,生成所有落在查询时间范围内的目标时间点,完全匹配你举例的4小时间隔取0点、20点、16点等数据的需求 - 保留了原有逻辑中的分钟匹配规则,和旧逻辑行为一致
- 注意:如果你的
created字段保存的时间精确到秒/微秒且不是固定为0,可以将created__in替换为按小时、分钟组合筛选即可适配。
方案2:数据库层模运算筛选(适合超大时间范围查询)
如果查询的时间范围特别大,希望完全在数据库层完成筛选,可以用Django的时间提取函数配合模运算实现,更贴合原有逻辑的分钟匹配规则,不限制秒级数值:
完整代码
from datetime import timedelta from django.utils import timezone from django.db.models import F, ExtractHour def _get_prices_per_time_slice(self, last_hours=24, time_slice_in_hours=4): now = timezone.now() end_time = now.replace(second=0, microsecond=0) start_time = end_time - timedelta(hours=last_hours) end_hour = end_time.hour qset = Price.objects.filter( created__range=[start_time, end_time], created__minute=end_time.minute ).annotate( created_hour=ExtractHour('created') ).filter( (F('created_hour') - end_hour) % time_slice_in_hours == 0 ).values('price') return [r['price'] for r in qset]
注意事项
- 需要Django 3.1及以上版本支持
ExtractHour函数 - 模运算会自动处理跨天的小时差值负数问题,无需额外适配
- 兼容MySQL、PostgreSQL等主流数据库的时间函数逻辑
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

