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

Django聚合Jalali周乘客数问题:__week返回公历周数而非波斯历周数

解决方案

因为django_jalali的jDateField在数据库中仍以公历日期存储,Django默认的__week查询会调用数据库的公历周数函数,导致结果不符合预期。针对PostgreSQL环境,有以下几种可行方案:

方案1:直接使用PostgreSQL波斯历日期函数(推荐)

利用PostgreSQL的to_char函数,指定波斯历日历(NLS_CALENDAR=PERSIAN)来提取周数,通过Django的Func表达式实现:

from django.db.models import Func, F, Sum

queryset = TravelReport.objects.annotate(
    jalali_week=Func(
        F('travel_date'),
        function='to_char',
        template="to_char(%(expressions)s, 'IW', 'NLS_CALENDAR=PERSIAN')"
    )
).values('jalali_week').annotate(total_passengers=Sum('passengers'))

说明:

  • 'IW'表示ISO标准周数(每周从周一开始),如果需要波斯历的其他周数格式,可替换为'%W'(每周从周日开始,周范围1-53),根据需求调整。
  • 该方案直接在数据库层面计算,效率高,适合大数据量场景。

方案2:自定义Jalali周数函数(复用性强)

封装一个可复用的自定义数据库函数,避免重复写SQL模板:

from django.db.models import Func

class JalaliWeek(Func):
    function = 'to_char'
    template = "to_char(%(expressions)s, 'IW', 'NLS_CALENDAR=PERSIAN')"

# 使用方式
queryset = TravelReport.objects.annotate(
    jalali_week=JalaliWeek(F('travel_date'))
).values('jalali_week').annotate(total_passengers=Sum('passengers'))

方案3:Python层面处理(仅小数据量适用)

如果数据量不大,可以先将数据查询到内存中,用jdatetime转换后分组聚合:

from jdatetime import date as jdate

reports = TravelReport.objects.all()
weekly_totals = {}

for report in reports:
    # 将存储的公历日期转换为波斯历日期
    jalali_date = jdate.fromgregorian(date=report.travel_date)
    week_num = jalali_date.isocalendar()[1]  # 获取波斯历周数
    if week_num not in weekly_totals:
        weekly_totals[week_num] = 0
    weekly_totals[week_num] += report.passengers

# 转换为类似QuerySet的结构
result = [{'week': k, 'total_passengers': v} for k, v in weekly_totals.items()]

注意:

  • 此方案需要将所有数据加载到内存,数据量大时会严重影响性能,仅适合小规模数据场景。

内容的提问来源于stack exchange,提问作者Druid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:35:41