如何使用Django 2.2 ORM实现指定多表关联查询?
Django 2.2 ORM 实现指定SQL查询方案
首先明确模型间的关联关系(基于你的SQL推导,若实际模型有差异,替换对应字段/关联名称即可):
Run是关联中心,主键id,反向关联testinfo_set(对应TestInfo)、suiteinfo_set(对应SuiteInfo)TestInfo外键关联Run(run_id)、Test(test_id),反向关联toolinfo_set(对应ToolInfo)SuiteInfo外键关联Run(run_id)ToolInfo外键关联TestInfo(test_info_id)Test有字段path
可行方案:用 values() 直接生成扁平结果
因为你需要的是像原生SQL那样的扁平行数据(而非嵌套的模型对象),values() 可以直接跨表引用字段,自动生成对应JOIN,完美匹配你的SQL逻辑:
from django.db.models import F # 执行查询,返回字典列表,每个字典对应SQL的一行 query_result = Run.objects.filter(id=34).values( 'id', # run.id test_path=F('testinfo_set__test__path'), test_info_id=F('testinfo_set__id'), tool_info_id=F('testinfo_set__toolinfo_set__id'), suite_info_id=F('suiteinfo_set__id') )
为什么这个方案有效:
- 自动生成和你原生SQL一致的JOIN语句,返回的结果结构完全匹配需求
- 直接得到扁平的字段集合,不需要手动处理嵌套的关联对象
为什么你之前的方法没生效:
select_related:仅支持正向外键/一对一关联,无法处理Run到TestInfo、SuiteInfo这类反向多对多关联,所以会报字段错误prefetch_related:是分两次查询(先查Run,再查关联表),然后在Python端把关联对象绑定到Run实例上,得到的是嵌套的对象集合,无法直接生成你需要的扁平行数据
特殊情况处理
如果存在一个TestInfo对应多个ToolInfo或一个Run对应多个SuiteInfo的场景,上面的查询会生成笛卡尔积(和你的原生SQL行为一致)。如果需要聚合多值(比如把多个ToolInfo id拼成数组),可以用PostgreSQL的聚合函数(Django 2.2支持):
from django.contrib.postgres.aggregates import ArrayAgg query_result = Run.objects.filter(id=34).annotate( test_paths=ArrayAgg('testinfo_set__test__path'), tool_info_ids=ArrayAgg('testinfo_set__toolinfo_set__id'), suite_info_ids=ArrayAgg('suiteinfo_set__id') ).values('id', 'test_paths', 'tool_info_ids', 'suite_info_ids')
内容的提问来源于stack exchange,提问作者kdubs
相关产品推荐
相关产品推荐

