如何在Django中按周六起始的周分组统计Load数据?
解决方案:无需新增字段,通过ORM调整日期计算自定义周起始
不需要新增数据表字段,直接利用Django ORM的数据库函数就能实现以周六为起始日的周分组,针对不同数据库有以下实现方式:
针对MySQL数据库
MySQL的WEEK()函数支持指定周起始模式,其中模式6对应“周六为起始日、周五为结束日”。我们可以封装一个自定义Func来调用该模式:
from django.db.models import Func from django.db.models import ExtractYear, Count, Sum, ExpressionWrapper, F, NullIf from django.db.models.fields import DecimalField # 自定义周计算函数,指定周六为起始 class SaturdayStartWeek(Func): function = 'WEEK' template = "%(function)s(%(expressions)s, 6)" # 修改后的查询语句 loads_of_dedicated_customers = Load.objects.filter( customer__is_dedicated=True ).exclude( load_status='Cancelled' ).values( 'customer__name' ).annotate( year=ExtractYear('drop_date'), week=SaturdayStartWeek('drop_date') ).annotate( loads_count=Count('id'), sum_revenue=Sum('billable_amount'), sum_miles=Sum('total_miles'), rate_per_mile=ExpressionWrapper( F('sum_revenue') / NullIf(F('sum_miles'), 0), output_field=DecimalField(max_digits=7, decimal_places=2) ), )
针对PostgreSQL数据库
PostgreSQL的EXTRACT(WEEK)默认以周日为起始日,我们可以通过将日期加1天的方式,把周六映射为新一周的周日,从而让周六到下周五被归为同一周:
from django.db.models import Func, F, Value from django.db.models import ExtractYear, Count, Sum, ExpressionWrapper, NullIf from django.db.models.fields import IntegerField, DecimalField # 自定义周计算函数,实现周六起始 class SaturdayStartWeek(Func): template = "EXTRACT(WEEK FROM (%(expressions)s + INTERVAL '1 day'))" output_field = IntegerField() # 年份对应调整,确保周与年份匹配 class SaturdayStartYear(Func): template = "EXTRACT(YEAR FROM (%(expressions)s + INTERVAL '1 day'))" output_field = IntegerField() # 修改后的查询语句 loads_of_dedicated_customers = Load.objects.filter( customer__is_dedicated=True ).exclude( load_status='Cancelled' ).values( 'customer__name' ).annotate( year=SaturdayStartYear('drop_date'), week=SaturdayStartWeek('drop_date') ).annotate( loads_count=Count('id'), sum_revenue=Sum('billable_amount'), sum_miles=Sum('total_miles'), rate_per_mile=ExpressionWrapper( F('sum_revenue') / NullIf(F('sum_miles'), 0), output_field=DecimalField(max_digits=7, decimal_places=2) ), )
跨数据库通用思路
如果需要兼容多数据库,可以通过Case和When判断当前数据库类型,再选择对应的周计算逻辑,核心都是通过日期偏移调整周的起始基准,避免新增冗余字段。
内容的提问来源于stack exchange,提问作者Valeriu
相关产品推荐
相关产品推荐

