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

如何在Django中从TableA出发关联TableB和TableC执行内连接查询

从TableA出发关联查询TableB和TableC的Django实现

需求说明

需要实现等价于以下SQL的查询逻辑,从TableA出发关联查询对应的TableB和TableC数据,最终返回结果包含TableA所有属性 + TableB所有属性 + TableC所有属性:

select * from TableA inner join TableB on TableA.id=TableB.table_a_id inner join TableC on TableA.id=TableC.table_a_id where TableA.id=3

现有Django模型与序列化器

from django.db import models
from rest_framework import serializers

class Users(models.Model):
    first_name = models.CharField(max_length=255, blank=True, null=True, unique=True)
    last_name = models.CharField(max_length=255, blank=True, null=True)

class TableA(models.Model):
    user = models.ForeignKey(Users, on_delete=models.CASCADE)
    atrribute_a_1 = models.CharField(max_length=255, blank=True, null=True, unique=True)
    atrribute_a_2 = models.CharField(max_length=255, blank=True, null=True)

class TableB(models.Model):
    user = models.ForeignKey(Users, on_delete=models.CASCADE)
    table_a_id = models.ForeignKey(TableA, on_delete=models.CASCADE)
    atrribute_b_1 = models.DecimalField(max_digits=100, decimal_places=8, default=0)
    atrribute_b_2 = models.DecimalField(max_digits=100, decimal_places=8, default=0)
    atrribute_b_3 = models.DecimalField(max_digits=100, decimal_places=8, default=0)

class TableC(models.Model):
    user = models.ForeignKey(Users, on_delete=models.CASCADE)
    table_a_id = models.ForeignKey(TableA, on_delete=models.CASCADE)
    atrribute_c_1 = models.DecimalField(max_digits=100, decimal_places=8, default=0)
    atrribute_c_2 = models.DecimalField(max_digits=100, decimal_places=8, default=0)

class TableBSerializer(serializers.ModelSerializer):
    class Meta:
        model = TableB
        fields = '__all__'

class TableCSerializer(serializers.ModelSerializer):
    class Meta:
        model = TableC
        fields = '__all__'

解决方案

1. 调整查询语句

由于TableB和TableC通过外键关联到TableA,从TableA出发查询关联数据属于反向一对多查询,需要用prefetch_related预取关联集合,避免N+1查询问题:

# 查询id=3的TableA对象,并预取对应的TableB、TableC数据
table_a_instance = TableA.objects.prefetch_related('tableb_set', 'tablec_set').get(id=3)

注:tableb_set和tablec_set是Django自动生成的反向关联名称,格式为模型名小写_set;如果需要自定义名称,可以在ForeignKey中添加related_name参数(比如table_a_id = models.ForeignKey(TableA, on_delete=models.CASCADE, related_name='tablebs'))。

2. 修改TableASerializer以包含关联字段

原序列化器只返回TableA自身字段,需要嵌套TableBSerializer和TableCSerializer来关联输出对应的子表数据:

class TableASerializer(serializers.ModelSerializer):
    # 嵌套序列化TableB和TableC的集合(many=True表示多个关联对象)
    tableb_set = TableBSerializer(many=True)
    tablec_set = TableCSerializer(many=True)

    class Meta:
        model = TableA
        fields = '__all__'

3. 执行序列化

serializer = TableASerializer(table_a_instance)
result_data = serializer.data

补充说明

  • 如果业务场景中一个TableA仅对应一个TableB和一个TableC,可将many=True改为many=False,同时给外键添加unique=True约束;
  • 若需要完全复刻SQL的笛卡尔积扁平结构(每条记录是TableA+TableB+TableC的组合),可使用values()方法手动拼接字段,但嵌套序列化的REST风格返回结构更符合接口设计规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 02:25:22