如何用单条Django查询统计各航班的已完成检查清单数量
问题描述
给定以下Django模型:
class Flight: # 模型其他字段省略,仅展示关联关系 pass class Checklist: flight = ForeignKey(Flight, on_delete=models.CASCADE) class Item: checklist = ForeignKey(Checklist, on_delete=models.CASCADE) completed = BooleanField()
需求是统计每个Flight对应的已完成Checklist数量,判断Checklist完成的规则为:该Checklist下的所有Item的completed字段均为True。
已知针对Checklist可通过以下代码标注是否完成:
Checklist.objects.annotate( is_complete=~Exists(Item.objects.filter( completed=False, checklist_id=OuterRef('pk'), )) )
现需针对Flight实现类似逻辑,理想情况下使用单条查询,大致结构如下:
Flight.objects.annotate( completed_checklists=Count( Checklist.objects.annotate(<is complete annotation here>).filter(is_complete=True) ) )
解决方案
提供两种单查询实现方式,核心逻辑均为判断Checklist是否不存在未完成的Item:
方法一:利用FilteredRelation过滤后计数
from django.db.models import Exists, OuterRef, Count, FilteredRelation Flight.objects.annotate( # 给关联的Checklist集合添加已完成的过滤关系 completed_checklists_rel=FilteredRelation( 'checklist_set', condition=~Exists( Item.objects.filter( checklist_id=OuterRef('checklist_set__pk'), completed=False ) ) ) ).annotate( # 对过滤后的已完成Checklist进行计数 completed_checklists=Count('completed_checklists_rel') )
方法二:在Count中嵌套子查询
from django.db.models import Exists, OuterRef, Count, Subquery Flight.objects.annotate( completed_checklists=Count( Subquery( Checklist.objects.filter( flight=OuterRef('pk'), # 直接判断当前Checklist无未完成Item ~Exists(Item.objects.filter( checklist_id=OuterRef('pk'), completed=False )) ).values('pk') ) ) )
逻辑说明
- 两种方案都通过
~Exists(...)判断Checklist是否不存在completed=False的Item,以此标记该Checklist为已完成。 - 方法一先通过
FilteredRelation筛选出每个Flight下的已完成Checklist集合,再对该集合计数;方法二则直接通过子查询获取符合条件的Checklist主键,再统计数量。 - 两种方式都能生成单条SQL查询,避免多次数据库交互,性能更优。
内容的提问来源于stack exchange,提问作者user15656060
相关产品推荐
相关产品推荐

