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
相关产品推荐
相关产品推荐

