Django ORM实现Parent与多子表、关联表的Inner Join多表连接查询
Django ORM多表内连接查询实现方案
你给出的SQL是以Parent表为主表,内联所有子表及关联的OtherTable,要求返回同时存在Child1、Child2、Child3关联记录的Parent数据,Django ORM可通过以下方式实现等效查询:
核心实现代码
因为Parent到三个Child表是反向外键关联,默认反向关联名为child1_set、child2_set、child3_set(未自定义related_name的前提下),通过filter触发反向关联的内连接,配合select_related处理Child3到OtherTable的正向关联即可:
# 如需平铺返回所有关联表字段,等效于SQL的select * from django.db.models import F queryset = Parent.objects.filter( # 触发三个子表的内连接,仅保留同时有三类子表关联的Parent记录 child1__isnull=False, child2__isnull=False, child3__isnull=False # 预加载Child3关联的OtherTable,走内连接 ).select_related( "child3__other_table" # 指定返回所有需要的字段,双下划线表示跨表取字段 ).values( # Parent表字段示例,替换为实际字段名 "id", "parent_field1", "parent_field2", # Child1表字段 "child1__id", "child1__field1", # Child2表字段 "child2__id", "child2__field1", # Child3表字段 "child3__id", "child3__field1", # OtherTable表字段 "child3__other_table__id", "child3__other_table__field1" ) # 打印生成的SQL和参数验证 print(queryset.query.sql_with_params())
其他使用场景
如果你需要返回对象实例而非平铺字段,可改用prefetch_related预加载所有关联对象,避免N+1查询:
queryset = Parent.objects.filter( child1__isnull=False, child2__isnull=False, child3__isnull=False ).prefetch_related( "child1_set", "child2_set", "child3_set", "child3__other_table" ) # 遍历访问关联对象不会触发额外查询 for parent in queryset: child1_items = parent.child1_set.all() child2_items = parent.child2_set.all() child3_items = parent.child3_set.all() for child3 in child3_items: other_item = child3.other_table
注意事项
- 如果外键字段已设置
null=False,filter中可以省略__isnull=False,直接引用反向关联字段即可触发内连接 select_related仅支持正向外键、一对一关联的表连接,反向一对多关联需要通过filter/annotate触发连接,或用prefetch_related预加载数据
内容的提问来源于stack exchange,提问作者Amir Abdollahi
相关产品推荐
相关产品推荐

