Django如何动态设置annotate中Case的When条件then值?
问题描述
我有一个葡萄牙语月份字典:
MONTHS = { 1: "Janeiro", 2: "Fevereiro", 3: "Março", 4: "Abril", 5: "Maio", 6: "Junho", 7: "Julho", 8: "Agosto", 9: "Setembro", 10: "Outubro", 11: "Novembro", 12: "Dezembro", }
需要在Django QuerySet里通过annotate把last_installment_month字段的数字值转换成对应的月份字符串。目前用Case+When的写法是手动逐个写条件:
queryset = queryset.annotate( last_installment_month_as_string=Case( When(last_installment_month=1, then=Value(MONTHS[1])), When(last_installment_month=2, then=Value(MONTHS[2])), When(last_installment_month=3, then=Value(MONTHS[3])), When(last_installment_month=4, then=Value(MONTHS[4])), When(last_installment_month=5, then=Value(MONTHS[5])), When(last_installment_month=6, then=Value(MONTHS[6])), When(last_installment_month=7, then=Value(MONTHS[7])), When(last_installment_month=8, then=Value(MONTHS[8])), When(last_installment_month=9, then=Value(MONTHS[9])), When(last_installment_month=10, then=Value(MONTHS[10])), When(last_installment_month=11, then=Value(MONTHS[11])), When(last_installment_month=12, then=Value(MONTHS[12])), ) )
但想通过循环动态生成这些When条件,尝试了下面的写法但无效:
for key, value in MONTHS.items(): queryset = queryset.annotate( last_installment_month_as_string=Case( When(last_installment_month=key, then=Value(value)) ) )
求正确的动态生成方式。
解决方案
你之前的循环写法每次都会重复覆盖last_installment_month_as_string注解,且每次仅生成单个When条件,因此无法实现预期效果。正确的做法是先一次性生成所有When对象的列表,再将这个列表传入Case:
from django.db.models import Case, When, Value # 遍历MONTHS生成所有When条件 when_conditions = [ When(last_installment_month=key, then=Value(value)) for key, value in MONTHS.items() ] # 将条件列表拆包传给Case,完成注解 queryset = queryset.annotate( last_installment_month_as_string=Case(*when_conditions) )
补充说明
- 使用列表推导式批量生成
When实例,确保每个数字月份都对应正确的字符串值 - 用
*运算符将列表拆包为Case的参数,效果与手动编写12个When完全一致 - 若需要处理
last_installment_month为空的场景,可以给Case添加default参数,例如default=Value("")
内容的提问来源于stack exchange,提问作者Ives Furtado
相关产品推荐
相关产品推荐

