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

Django使用annotate对DurationField求和并转换为小数小时

Django DurationField求和后转十进制小时实现方案

你当前写法有个细节问题:如果要对全表所有记录的Time字段求总和,应该用aggregate()而不是annotate()——annotate()是给每一行查询结果追加聚合字段,aggregate()才是直接返回全表聚合后的单值结果。

两种实现方式按需选择:

方案1:数据库层直接计算返回小时值(推荐)

直接在ORM查询阶段完成时间转小时的计算,查询返回的结果直接是你要的十进制小时数,不需要后续额外转换:

from datetime import timedelta
from django.db.models import Sum
from django.db.models.functions import Extract

# 聚合查询,同时返回原始总时长、十进制小时数
result = Task.objects.aggregate(
    total_timedelta=Sum('Time', default=timedelta(0)),
    total_hours=Extract(Sum('Time', default=timedelta(0)), 'epoch') / 3600
)

代码说明:

  • Extract(聚合结果, 'epoch')会把Sum计算得到的时间间隔直接转为总秒数
  • 总秒数除以3600即可得到十进制小时值,比如总秒数为5400时,计算结果就是1.5,完全匹配你的预期
  • 给Sum传入default=timedelta(0)是为了避免表内无数据、或存在Time字段为NULL的记录时返回None导致计算报错

方案2:Python层转换timedelta结果

如果你已经通过Sum拿到了timedelta类型的总时长,直接调用timedelta内置方法计算即可:

from datetime import timedelta
from django.db.models import Sum

# 拿到总时长timedelta对象
total_td = Task.objects.aggregate(total=Sum('Time', default=timedelta(0)))['total']
# 转十进制小时
total_hours = total_td.total_seconds() / 3600

比如total_td为timedelta(seconds=5400)时,total_td.total_seconds()会返回5400,除以3600后得到1.5。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:06:26