使用Django ORM的Extract系列函数对QuerySet按时间分组的技术问询
用Django的Extract系列函数实现DateTime字段的GROUP BY分组
我来帮你搞定这个按日期时间分组统计的需求~结合你给出的CustomData模型,下面直接上实用的实现方案:
基础示例:按单一时间粒度分组
比如你想按**创建日期的“日”**分组,统计每组的number总和以及数据条数,可以这么写:
from django.db.models import Sum, Count from django.db.models.functions import ExtractDay # 先过滤掉created为null的数据(避免无效分组),再提取日期的“日”维度 daily_stats = CustomData.objects.filter(created__isnull=False).annotate( # 从created字段中提取“日”(比如1号、2号...31号) day_of_month=ExtractDay('created') ).values('day_of_month').annotate( # 统计每组的number总和 total_number=Sum('number'), # 统计每组的数据条数 record_count=Count('id') ).order_by('day_of_month') # 按日期顺序排序
进阶:按多时间维度组合分组
如果需要更精细的粒度,比如年-月-日-小时这样的组合分组,用通用的Extract函数会更灵活(可以指定任意时间组件):
from django.db.models import Sum from django.db.models.functions import Extract hourly_stats = CustomData.objects.filter(created__isnull=False).annotate( year=Extract('created', 'year'), month=Extract('created', 'month'), day=Extract('created', 'day'), hour=Extract('created', 'hour') ).values('year', 'month', 'day', 'hour').annotate( total_number=Sum('number') ).order_by('year', 'month', 'day', 'hour')
这里的Extract('created', 'year')和专门的ExtractYear('created')效果完全一致,通用Extract函数支持的时间组件包括:year、month、day、hour、minute、second等。
更实用的完整日期分组
如果你的需求是按**完整的日期(YYYY-MM-DD)**分组,而不是当月的第几天,推荐用TruncDate函数(比ExtractDay更直观,不会跨月重复):
from django.db.models import Sum from django.db.models.functions import TruncDate date_stats = CustomData.objects.filter(created__isnull=False).annotate( # 将created截断为日期对象(比如2024-05-20) created_date=TruncDate('created') ).values('created_date').annotate( total_number=Sum('number') ).order_by('created_date')
同理,如果你需要按小时完整时间(比如2024-05-20 14:00:00)分组,可以用TruncHour,分钟粒度用TruncMinute,用法和TruncDate一致。
关键注意点
- 一定要先过滤
created__isnull=False,否则分组结果里会出现null的分组项,影响统计准确性; values()方法里的字段是分组的依据,必须和前面annotate定义的字段对应;- 最后加上
order_by()保证分组结果按时间顺序排列,避免出现乱序。
内容的提问来源于stack exchange,提问作者Vladislav Zhdanov
相关产品推荐
相关产品推荐

