如何在Django查询中计算距截止日期剩余天数?遇Case报错求解
问题解决方案
错误原因及修复步骤
Case() got an unexpected keyword argument 'default'
Django的Case表达式不支持default参数,对应的默认分支参数是otherwise,替换即可。TypeError: QuerySet.annotate() received non-expression(s):
你用Value()包裹了F()表达式的计算结果,这是错误的。F()本身就是数据库可识别的表达式,无需用Value()包装——Value()仅用于包裹常量值(如数字、字符串)。
修正后的代码
方案1:返回天数差(timedelta类型)
from django.db.models import Case, When, F, Value, DurationField from django.db.models.functions import TruncDate, Now query_list = file.qs.annotate( overdue=Case( # 截止日期晚于当前日期,计算剩余时间差 When(due_date__gt=TruncDate(Now()), then=F('due_date') - TruncDate(Now())), # 截止日期为空,返回None When(due_date__isnull=True, then=Value(None)), # 其他情况(已逾期或当天到期)返回0 otherwise=Value(0), output_field=DurationField() ) ).values_list('overdue', ...)
方案2:返回整数天数
如果需要直接得到剩余天数的整数而非时间间隔对象,可以使用ExtractDay函数:
from django.db.models import Case, When, F, Value, IntegerField from django.db.models.functions import TruncDate, Now, ExtractDay query_list = file.qs.annotate( overdue_days=Case( When(due_date__gt=TruncDate(Now()), then=ExtractDay(F('due_date') - TruncDate(Now()))), When(due_date__isnull=True, then=Value(None)), otherwise=Value(0), output_field=IntegerField() ) ).values_list('overdue_days', ...)
额外说明
- 使用
TruncDate(Now())替代timezone.now().date():确保使用数据库服务器的当前日期,避免Python运行环境与数据库的时间差问题。 - 若
due_date是DateTimeField,TruncDate会自动提取日期部分进行比较,结果更准确。 - 如果不想返回
None,可以用Value(-1)等特殊值标记due_date为空的情况,避免可能的类型兼容问题。
内容的提问来源于stack exchange,提问作者edche
相关产品推荐
相关产品推荐

