在Django中如何计算关联表datetime字段差值的平均值?
报错原因&解决方案
你遇到的报错和计算逻辑错误来自三个核心问题,按顺序修改即可:
1. 反向关联名称不匹配(报错的直接原因)
你在Orders模型的item外键字段设置了related_name='gig',意味着Gigs实例反向查询关联订单的字段名是gig,不是你代码里写的orders,所以Django找不到orders字段才会报对应错误。
如果想要更符合语义的命名,建议先修改buyer应用下Models.py的Orders字段:
# 将related_name从gig改成orders,后续写代码更不容易混淆 item = models.ForeignKey(Gigs,default=None, on_delete=models.CASCADE,related_name='orders')
修改后执行makemigrations和migrate更新配置即可。
2. 时间差计算逻辑修正
不能直接对字段名字符串做减法,需要用Django的F表达式取字段值,配合ExpressionWrapper指定时间差输出类型,同时可以直接在查询层做注解避免N+1性能问题。
首先修改Views.py,导入依赖并改写查询集:
from django.db.models import F, Avg, ExpressionWrapper, DurationField class RetrieveGigsAPI(GenericAPIView, RetrieveModelMixin): def get_queryset(self): return Gigs.objects.annotate( # 直接在查询时注解计算好平均耗时,避免每个实例单独查库 _average_completionTime=Avg( ExpressionWrapper( F('orders__order_completed_time') - F('orders__order_start_time'), output_field=DurationField() ), # 可选:添加过滤条件,只统计已完成的订单 filter=Q(orders__status='completed') ) ) serializer_class = GigsSerializerWithAvgTime permission_classes = (AllowAny,) def get(self, request , *args, **kwargs): return self.retrieve(request, *args, **kwargs)
3. 修正Gigs模型的属性逻辑
修改seller应用下Models.py的average_completionTime属性,直接复用查询层注解的结果,不需要重复计算:
@property def average_completionTime(self): # 优先取查询时注解好的结果,没有注解的情况再兜底计算 if hasattr(self, '_average_completionTime'): # 可选:如果需要返回分钟/秒数,在这里做转换:return self._average_completionTime.total_seconds() / 60 return self._average_completionTime # 兜底计算逻辑 from django.db.models import F, Avg, ExpressionWrapper, DurationField, Q return self.orders.filter(status='completed').aggregate( avg_time=Avg( ExpressionWrapper( F('order_completed_time') - F('order_start_time'), output_field=DurationField() ) ) )['avg_time']
可选优化
如果需要把时间差格式化成易读的字符串,可以在序列化器的get_average_completionTime方法里做格式转换,不需要修改原有逻辑。
内容的提问来源于stack exchange,提问作者user16137336
相关产品推荐
相关产品推荐

