如何在Django QuerySet的Case中用同一When生成多个注解?
在Django QuerySet中通过一次条件逻辑生成两个独立注解
首先明确:Django的Case操作无法直接在单次调用中生成两个独立的注解字段,但可以通过复用条件逻辑的方式,避免重复编写相同的判断条件,同时得到独立的status和reason注解。
解决方案:封装共用条件,复用逻辑
核心思路是把每个判断条件封装成独立的Q对象,然后为status和reason分别创建Case时复用这些条件,避免重复写冗余的条件代码。
步骤1:封装共用的判断条件
先把所有需要判断的条件提取为单独的Q对象,这样后续的When语句可以直接复用:
# 提取共用的判断条件 q_inactive = Q(is_active=False) q_only_recently_published = Q(is_old_published_ad_exists=False) & Q(is_recently_published_ads_exists=True) q_no_published_ad = Q(is_old_published_ad_exists=False) & Q(is_recently_published_ads_exists=False) q_not_enough_booking = Q(...) # 替换成你的实际条件 q_low_booking_cnt = Q(...) # 替换成你的实际条件
步骤2:复用条件生成When语句
基于封装好的Q对象,分别为status和reason创建对应的When语句,不用重复编写条件:
from django.db.models import Value, When, Case # 生成status对应的When列表 status_whens = [ When(q_inactive, then=Value(stats_cts.INACTIVE)), When(q_only_recently_published, then=Value(stats_cts.PENDING)), When(q_no_published_ad, then=Value(stats_cts.PENDING)), When(q_not_enough_booking, then=Value(...)), # 替换成你的实际status值 When(q_low_booking_cnt, then=Value(...)), # 替换成你的实际status值 ] # 生成reason对应的When列表 reason_whens = [ When(q_inactive, then=Value(None)), When(q_only_recently_published, then=Value(OwnerStatsStatusReason.RECENTLY_SUSPENDED)), When(q_no_published_ad, then=Value(OwnerStatsStatusReason.NO_BOOKABLE_TO_MODERATE)), When(q_not_enough_booking, then=Value(...)), # 替换成你的实际reason值 When(q_low_booking_cnt, then=Value(...)), # 替换成你的实际reason值 ]
步骤3:执行注解
最后在QuerySet的annotate中分别传入两个Case,生成独立的注解字段:
my_qs.annotate( dynamic_status_deadfish=Case( *status_whens, default=Value(stats_cts.DEFAULT_STATUS), # 替换成你的默认status值 ), dynamic_status_deadfish_reason=Case( *reason_whens, default=Value(OwnerStatsStatusReason.DEFAULT_REASON), # 替换成你的默认reason值 ) )
进阶优化:封装生成逻辑
如果条件较多,可以进一步封装成函数,减少重复代码:
def get_status_reason_whens(condition, status_val, reason_val): """生成对应条件的status和reason When对象""" return ( When(condition, then=Value(status_val)), When(condition, then=Value(reason_val)) ) # 批量生成各条件的When对 condition_pairs = [ (q_inactive, stats_cts.INACTIVE, None), (q_only_recently_published, stats_cts.PENDING, OwnerStatsStatusReason.RECENTLY_SUSPENDED), (q_no_published_ad, stats_cts.PENDING, OwnerStatsStatusReason.NO_BOOKABLE_TO_MODERATE), (q_not_enough_booking, ..., ...), # 补充你的条件和对应值 (q_low_booking_cnt, ..., ...), # 补充你的条件和对应值 ] # 拆分status和reason的When列表 status_whens = [] reason_whens = [] for cond, status, reason in condition_pairs: status_when, reason_when = get_status_reason_whens(cond, status, reason) status_whens.append(status_when) reason_whens.append(reason_when) # 执行注解 my_qs.annotate( dynamic_status_deadfish=Case(*status_whens, default=Value(stats_cts.DEFAULT_STATUS)), dynamic_status_deadfish_reason=Case(*reason_whens, default=Value(OwnerStatsStatusReason.DEFAULT_REASON)) )
这种方式既保留了独立注解字段的易用性,又避免了重复编写条件逻辑的冗余,比使用HStoreField更直接,无需处理序列化。
内容的提问来源于stack exchange,提问作者ogr
相关产品推荐
相关产品推荐

