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

Django中如何用最少数据库查询实现父表与子表左连接?

问题

我希望通过最少的数据库查询实现左连接,获取所有State(州)记录及其关联的City(城市)记录(若无关联城市则显示空值)。尝试过.select_related、原生SQL查询(RawQuery)以及Q对象,但遇到以下问题:

  1. 使用.select_related的代码cities_states = City.objects.all().select_related('state').order_by('state_id')无法获取无关联城市的State(如Illinois);
  2. 使用原生SQL查询能得到所需数据,但无法区分State和City表中同名的字段(如id、name),不知如何单独获取City的id或name。

相关模型代码:

class State(models.Model):
  name = models.CharField(max_length=25)
  abbreviation = models.CharField(max_length=2)

  def __str__(self):
    return str(self.id)


class City(models.Model):
  name = models.CharField(max_length=25)
  population = models.IntegerField()
  state = models.ForeignKey(State, related_name="cities", on_delete=models.CASCADE)

  def __str__(self):
    return str(self.id)

期望结果:所有州(包括无城市的州)与对应城市展开为行,无城市的州对应城市字段为空。


解决方案

1. 如何用最少的数据库查询获取所需数据?

要实现1次数据库查询完成左连接需求,直接使用原生SQL左连接是最优方案;如果接受2次高效查询(性能差异极小),也可以用Django ORM的prefetch_related结合Python层面的结果展开:

方法一:原生SQL左连接(1次查询)

从State表出发编写左连接SQL,确保包含所有州记录:

sql = '''
SELECT 
    S.id, S.name, S.abbreviation,
    C.id AS city_id, C.name AS city_name, C.population, C.state_id
FROM "state" S
LEFT JOIN "city" C ON S.id = C.state_id
ORDER BY S.id ASC
'''

results = State.objects.raw(sql)

方法二:Django ORM + Python展开(2次查询)

用prefetch_related预加载所有关联城市,再在Python中遍历生成目标格式结果,更符合Django ORM使用习惯:

# 两次查询:一次获取所有州,一次获取所有关联城市,ORM自动完成关联
states = State.objects.all().prefetch_related('cities').order_by('id')

# 展开结果为目标格式
expanded_results = []
for state in states:
    if state.cities.exists():
        for city in state.cities:
            expanded_results.append({
                'state_id': state.id,
                'state_name': state.name,
                'abbreviation': state.abbreviation,
                'city_id': city.id,
                'city_name': city.name,
                'population': city.population,
                'city_state_id': city.state_id
            })
    else:
        # 无关联城市的州填充空值
        expanded_results.append({
            'state_id': state.id,
            'state_name': state.name,
            'abbreviation': state.abbreviation,
            'city_id': None,
            'city_name': None,
            'population': None,
            'city_state_id': None
        })

2. 使用原生查询时,如何区分State和City表中的同名字段?

在SQL查询语句中给同名字段设置别名,通过别名区分不同表的字段即可:

  • 例如将City的id命名为city_id,name命名为city_name;
  • 遍历RawQuerySet时直接通过别名访问对应字段,避免字段覆盖。

示例代码:

sql = '''
SELECT 
    S.id AS state_id, S.name AS state_name, S.abbreviation,
    C.id AS city_id, C.name AS city_name, C.population, C.state_id AS city_state_id
FROM "state" S
LEFT JOIN "city" C ON S.id = C.state_id
ORDER BY S.id ASC
'''

for item in State.objects.raw(sql):
    print(f"州ID: {item.state_id}, 州名: {item.state_name}")
    print(f"城市ID: {item.city_id}, 城市名: {item.city_name}\n")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:00:39