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

Django ORM中非主键唯一约束外键的跨表查询问题

Django ORM中外键关联非主键唯一列时的跨表查询问题

问题核心

你的问题出在Django ForeignKey默认关联目标表的主键,但你的数据库里TableMoon.planet实际关联的是TablePlanet.name(带唯一约束的列),而非TablePlanet.planet_id(主键),导致ORM生成的SQL关联条件错误,返回空结果。

解决方案

修改Tablemoon模型中的外键字段,显式指定to_field='name',告诉Django该外键关联的是Tableplanet的name列:

from django.db import models

class Tableplanet(models.Model):
    planet_id = models.AutoField(primary_key=True, null=False)
    name = models.TextField(unique=True)
    classification = models.TextField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'tablePlanet'

class Tablemoon(models.Model):
    moon_id = models.AutoField(primary_key=True, null=False)
    # 新增to_field='name',指定关联目标表的name列
    planet = models.ForeignKey('Tableplanet', models.DO_NOTHING,
                               db_column='planet', blank=True, null=True,
                               to_field='name')
    name = models.TextField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'tableMoon'

验证查询

修改后,执行你最初的查询语句即可得到预期结果:

Tablemoon.objects.filter(planet__classification='inner_planet').values('name')

此时Django生成的SQL会与你提供的目标SQL完全一致:

SELECT "tableMoon"."name" FROM "tableMoon" INNER JOIN "tablePlanet" ON ("tableMoon"."planet" = "tablePlanet"."name") WHERE "tablePlanet"."classification" = 'inner_planet'

返回结果:<QuerySet [{'name': 'Moon'}, {'name': 'Phobos'}, {'name': 'Deimos'}]>

关于planet_id的困惑解释

你看到values()返回planet_id: 'Earth'是Django的默认行为:定义ForeignKey时,Django会自动给关联字段的内部标识加上_id后缀,但因为之前未指定to_field,Django错误认为关联的是主键planet_id,但实际数据库存储的是name值,因此出现矛盾显示。修改to_field后,values()会正常返回planet: 'Earth'。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 06:48:24