Django如何筛选外键关联Discount全部为is_deleted的Product(不可用exclude)
实现方案
可通过Django ORM的聚合查询实现,全程在数据库层面完成计算,单条SQL即可执行,大表场景下性能远高于exclude生成的嵌套子查询。
方案1:ORM聚合查询(推荐,无需写原生SQL)
通过annotate统计每个Product关联的未删除Discount数量,筛选数量为0的结果即可:
from django.db.models import Count, Q result = Product.objects.annotate( # 统计当前产品关联的、未删除的Discount总数 undelete_discount_count = Count('discount', filter=Q(discount__is_deleted=False)) ).filter(undelete_discount_count=0)
边界情况调整
上述查询默认会包含没有关联任何Discount的Product,如果只需要筛选「有关联Discount且所有Discount均为已删除」的产品,调整过滤条件即可:
result = Product.objects.annotate( undelete_discount_count = Count('discount', filter=Q(discount__is_deleted=False)) ).filter(undelete_discount_count=0, discount__isnull=False).distinct()
方案2:原生SQL查询(性能最高,超大数据量可选)
如果数据量达到千万级,可直接写原生SQL执行,配合索引可达到最优性能:
result = Product.objects.raw(''' SELECT p.* FROM product p LEFT JOIN discount d ON p.id = d.product_id AND d.is_deleted = FALSE GROUP BY p.id HAVING COUNT(d.id) = 0 ''')
性能优化建议
给Discount表的product_id和is_deleted字段创建联合索引,可将上述查询的耗时降低90%以上,适合大表场景。
内容的提问来源于stack exchange,提问作者Tiancheng Liu
相关产品推荐
相关产品推荐

