无外键关联的两个Django模型如何通过公共id字段执行Join查询?
无外键的Django模型按id关联查询的实现方案
下面给三种不同场景的实现方式:
- 方法1:
Subquery子查询(Django 1.11及以上版本支持,官方推荐的非原生SQL方案)
适合需要将一个模型的字段附加到另一个模型的查询结果中,示例为将Pilot的vehicle字段关联到匹配id的Person查询结果:
from django.db.models import OuterRef, Subquery # 构造子查询,匹配id相同的Pilot记录的vehicle字段 pilot_vehicle_subq = Pilot.objects.filter(id=OuterRef('id')).values('vehicle')[:1] # 主查询Person,关联附加vehicle字段 person_with_pilot = Person.objects.annotate( vehicle=Subquery(pilot_vehicle_subq) # 去掉下面的filter就是LEFT JOIN效果,保留就是INNER JOIN效果 ).filter(vehicle__isnull=False)
如果需要反向将Person的name字段关联到Pilot的查询结果,调换两个模型的位置即可。
- 方法2:原生SQL直接写JOIN逻辑
如果关联逻辑复杂,直接写原生SQL灵活性最高:
# INNER JOIN 示例,返回两个表中id一致的匹配记录 join_result = Person.objects.raw(''' SELECT p.id, p.name, pi.vehicle FROM 你的应用名_person p INNER JOIN 你的应用名_pilot pi ON p.id = pi.id ''')
注意将SQL中的你的应用名替换为两个模型所属的Django应用名,要LEFT JOIN仅需把INNER JOIN改成LEFT JOIN即可。
- 方法3:Python内存层面关联(仅适合两个表数据量都极小的场景)
不需要修改数据库查询逻辑,全量查询后在Python层做匹配:
# 全量查询两个表的数据 person_list = list(Person.objects.all()) pilot_id_map = {pilot.id: pilot for pilot in Pilot.objects.all()} # 手动匹配合并 join_result = [] for person in person_list: matched_pilot = pilot_id_map.get(person.id) if matched_pilot: join_result.append({ "id": person.id, "name": person.name, "vehicle": matched_pilot.vehicle })
注意:不推荐使用
extra方法实现关联,该接口已被Django官方标记为废弃,后续版本会被移除。
内容的提问来源于stack exchange,提问作者BesterRanX
相关产品推荐
相关产品推荐

