You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django无外键场景下如何连接两个模型生成指定JOIN SQL语句

Django无外键关联两个模型的实现方案

针对你需要的JOIN查询需求,有两种常用的实现方式,分别对应ORM原生调用和自定义SQL调用:

方案1:ORM原生实现(无需修改模型、无需写完整SQL)

通过Subquery+OuterRef组合,可以在不定义外键的情况下完成字段匹配关联,适合需要复用ORM链式调用、分页等能力的场景:

from django.db.models import OuterRef, Subquery

# 构造匹配子查询:关联Genome.query_id = Metadata.sample_id
metadata_subquery = Metadata.objects.filter(
    sample_id=OuterRef("query_id")
)[:1] # 因关联列不唯一,此处默认取匹配到的第一条,可根据业务调整筛选逻辑

# 给Genome查询结果追加关联的Metadata字段
queryset = Genome.objects.annotate(
    # 按需添加需要从Metadata表取的字段
    related_project_id=Subquery(metadata_subquery.values("project_id")),
    related_sample_id=Subquery(metadata_subquery.values("sample_id"))
)

# 访问示例:
for obj in queryset:
    print(obj.query_id, obj.related_project_id)

方案2:直接使用raw方法生成你需要的精确SQL

如果需要完全匹配你给出的JOIN语句,直接调用raw()方法即可,性能最优且可控性最高:

# 执行自定义JOIN SQL,返回Genome模型实例,自动携带关联的Metadata字段
queryset = Genome.objects.raw(
    "SELECT A.*, B.* FROM genome AS A JOIN metadata AS B ON A.query_id = B.sample_id"
)

# 访问示例:
for obj in queryset:
    # Genome表字段直接访问
    print(obj.query_id, obj.ref_id)
    # 关联的Metadata表字段也可直接访问
    print(obj.project_id, obj.sample_id)

注意事项:

  • 若两张表存在重名字段,需要在SELECT语句中手动指定别名避免字段覆盖,例如SELECT A.id AS genome_id, B.id AS metadata_id ...
  • 涉及动态参数时请使用params参数传递,避免SQL注入风险:
    queryset = Genome.objects.raw(
        "SELECT A.*, B.* FROM genome AS A JOIN metadata AS B ON A.query_id = B.sample_id WHERE B.project_id = %s",
        params=["目标项目ID"]
    )
    

扩展:直接获取字典格式结果

如果不需要返回模型实例,只需要原始查询结果,可以直接用数据库游标执行:

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("SELECT A.*, B.* FROM genome AS A JOIN metadata AS B ON A.query_id = B.sample_id")
    # 转换为字典列表格式
    columns = [col[0] for col in cursor.description]
    result = [dict(zip(columns, row)) for row in cursor.fetchall()]

内容的提问来源于stack exchange,提问作者Shale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 23:18:02