Django如何通过自定义selector函数过滤外键关联的有效实例
直接将A的有效判定条件通过跨关系前缀嵌入C的ORM查询即可,Django会自动处理多表关联逻辑,无需单独遍历B实例调用查询函数,避免产生N+1性能问题:
实现代码
from django.db.models import Q # 提前计算当日日期,避免多次调用get_now产生时间不一致 today = get_now().date() # 有效A实例的过滤Q对象,字段前加b__a__前缀关联C对应的A对象属性 valid_a_condition = ( Q(b__a__start_date__lte=today) & Q(b__a__end_date__gte=today) ) | ( Q(b__a__start_date__lte=today) & Q(b__a__end_date__isnull=True) ) | ( Q(b__a__start_date__isnull=True) & Q(b__a__end_date__isnull=True) ) C_with_valid_A = C.objects.filter( d_pk=d_pk, b__a__isnull=False ).filter(valid_a_condition).distinct()
补充说明
- 末尾加
distinct()是为了避免同一个C实例关联多个有效A实例时,查询结果出现重复条目 - 如果需要复用有效A的过滤逻辑,可以把Q对象抽成通用工具函数,同时适配单B实例查询和跨表查询场景:
def get_valid_a_q(prefix: str = "") -> Q: today = get_now().date() return ( Q(**{f"{prefix}start_date__lte": today}) & Q(**{f"{prefix}end_date__gte": today}) ) | ( Q(**{f"{prefix}start_date__lte": today}) & Q(**{f"{prefix}end_date__isnull": True}) ) | ( Q(**{f"{prefix}start_date__isnull": True}) & Q(**{f"{prefix}end_date__isnull": True}) ) # 原单个B实例查询有效A的函数可简化为 def get_valid_a(b_instance): return b_instance.a.filter(get_valid_a_q()) # 查C的时候直接传入前缀即可 C_with_valid_A = C.objects.filter( d_pk=d_pk, b__a__isnull=False, get_valid_a_q(prefix="b__a__") ).distinct()
- 原函数名
get_valid_a's不符合Python命名规范,建议调整为get_valid_a使用。
内容的提问来源于stack exchange,提问作者antpngl92
相关产品推荐
相关产品推荐

