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

Django序列化timedelta报无isoformat属性错误解决方案

报错根因

两个核心问题触发异常:

  1. 字段类型不匹配:Sum聚合模型中存储时长的work_time字段(对应ORM的DurationField,Python侧类型为datetime.timedelta)得到的total值是时间差对象,但序列化器中total被声明为serializers.TimeField。DRF的TimeField序列化时会主动调用值的isoformat()方法,而timedelta类型本身没有实现该方法,直接抛出你看到的属性错误。
  2. 查询集逻辑和序列化器不匹配:你在查询集中调用了.values(week=TruncWeek('timestamp'))做分组聚合,返回的结果字典仅包含week和total两个字段,序列化器声明的id、timestamp、work_time、user字段都不存在,就算解决类型问题,后续序列化也会触发字段缺失错误。
修复步骤

1. 替换total字段的序列化类型

累计工时是时间差,不是单日的时刻值,禁止使用TimeField处理(该类型无法正确表示超过24小时的时长,比如累计26小时会被错误显示为2点),二选一即可:

  • 快速适配:直接使用DRF内置的DurationField,自动将timedelta序列化为标准ISO时长格式:
    # 替换原来的total = serializers.TimeField()
    total = serializers.DurationField(read_only=True)
    
  • 自定义格式:如果需要输出固定的HH:MM:SS格式,自定义序列化字段做转换:
    class HmsDurationField(serializers.Field):
        def to_representation(self, value):
            total_sec = int(value.total_seconds())
            hour, rem = divmod(total_sec, 3600)
            minute, sec = divmod(rem, 60)
            return f"{hour:02d}:{minute:02d}:{sec:02d}"
    
    # 序列化器中total字段声明改为
    total = HmsDurationField(read_only=True)
    

2. 对齐查询集和序列化器的字段

你当前的查询是周维度的聚合统计,不是返回单条StaffWorkTime模型实例,不要复用原模型序列化器,单独写统计用的序列化器即可,同时修正查询集的筛选、排序逻辑:
修正后的视图查询集代码:

def get_queryset(self):
    week_start = datetime.date.today() - datetime.timedelta(days=datetime.date.today().weekday())
    # 原range筛选的week_end是当周周日0点,会漏掉周日当天的所有记录,补1天覆盖整周
    week_end = week_start + datetime.timedelta(days=7)
    queryset = StaffWorkTime.objects.filter(
        user_id=self.kwargs['pk'],
        timestamp__gte=week_start,
        timestamp__lt=week_end
    ).annotate(week=TruncWeek('timestamp'))\
    .values('week')\
    .annotate(total=Sum('work_time'))\
    .order_by('week') # 原order_by('timestamp')在分组后不存在该字段,会触发SQL错误
    return queryset

配套的统计序列化器代码:

class StaffWeekWorkTimeStatSerializer(serializers.Serializer):
    week = serializers.DateTimeField(format="%d-%m-%Y", read_only=True)
    total = HmsDurationField(read_only=True)
    # 如果需要返回用户信息,可在values中加入user关联字段,再在此处声明对应序列化字段

视图中把serializer_class替换为上述统计序列化器即可。

避坑提示

不要尝试把timedelta强转为time类型处理总时长,一旦单周总工时超过24小时,转换结果必然出错,所有累计时长场景都要基于timedelta类型做序列化转换。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:09:22