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

如何用Django Rest Framework实现关联表查询并返回合并JSON响应

嘿,我来帮你搞定这个DRF关联实体返回合并JSON的问题——其实核心就是用嵌套序列化器配合查询优化,完全能模拟SQL JOIN的效果,一步步给你拆解:

如何用Django Rest Framework返回关联实体的合并JSON响应

假设你的场景是:Alpha是主表,Beta通过外键关联到Alpha,当请求单个或所有Alpha数据时,要同时返回关联的所有Beta字段。

1. 先定义模型(models.py)

首先得把模型关系理清楚,记得给外键设置related_name,这是后续序列化时快速获取关联数据的关键:

from django.db import models

class Alpha(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

class Beta(models.Model):
    # 外键关联Alpha,related_name用来在Alpha实例中访问关联的Beta集合
    alpha = models.ForeignKey(Alpha, on_delete=models.CASCADE, related_name='betas')
    beta_field1 = models.CharField(max_length=50)
    beta_field2 = models.IntegerField()
    beta_field3 = models.BooleanField(default=False)

2. 编写序列化器(serializers.py)

这是实现合并数据的核心步骤,有两种常用方式,按需选择:

方式一:嵌套序列化器(推荐,简单直接)

先写Beta的序列化器,再把它嵌套到Alpha的序列化器里,用刚才的related_name作为字段名:

from rest_framework import serializers
from .models import Alpha, Beta

class BetaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Beta
        fields = ['id', 'beta_field1', 'beta_field2', 'beta_field3']  # 明确指定字段,别用__all__(生产环境要避免)

class AlphaSerializer(serializers.ModelSerializer):
    # many=True表示一个Alpha对应多个Beta,read_only=True表示只用于输出
    betas = BetaSerializer(many=True, read_only=True)

    class Meta:
        model = Alpha
        fields = ['id', 'name', 'description', 'created_at', 'betas']  # 把关联的betas字段加进去

方式二:SerializerMethodField(灵活自定义)

如果需要对关联的Beta数据做过滤、计算等自定义操作,就用这个:

class AlphaSerializer(serializers.ModelSerializer):
    betas = serializers.SerializerMethodField()

    class Meta:
        model = Alpha
        fields = ['id', 'name', 'description', 'created_at', 'betas']

    def get_betas(self, obj):
        # obj是当前的Alpha实例,这里可以自定义查询逻辑,比如只返回beta_field3为True的Beta
        filtered_betas = obj.betas.filter(beta_field3=True)
        return BetaSerializer(filtered_betas, many=True).data

3. 编写视图(views.py)

视图里重点要做性能优化,避免N+1查询问题——用prefetch_related一次性拉取关联的Beta数据,相当于SQL的JOIN操作:

示例1:单个Alpha详情视图(APIView)

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Alpha
from .serializers import AlphaSerializer

class AlphaDetailView(APIView):
    def get(self, request, pk):
        try:
            # prefetch_related('betas')一次性获取关联的所有Beta,避免多次查询
            alpha = Alpha.objects.prefetch_related('betas').get(pk=pk)
            serializer = AlphaSerializer(alpha)
            return Response(serializer.data)
        except Alpha.DoesNotExist:
            return Response({"error": "Alpha不存在"}, status=status.HTTP_404_NOT_FOUND)

示例2:高效的ViewSet(支持列表+详情)

如果需要同时支持“获取所有Alpha”和“获取单个Alpha”,用ViewSet更省心:

from rest_framework import viewsets
from .models import Alpha
from .serializers import AlphaSerializer

class AlphaViewSet(viewsets.ReadOnlyModelViewSet):
    # 提前用prefetch_related优化查询
    queryset = Alpha.objects.prefetch_related('betas').all()
    serializer_class = AlphaSerializer

4. 配置URL(urls.py)

根据你用的视图类型配置:

用APIView的情况:

from django.urls import path
from .views import AlphaDetailView

urlpatterns = [
    path('alpha/<int:pk>/', AlphaDetailView.as_view(), name='alpha-detail'),
]

用ViewSet的情况(需要DRF路由):

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import AlphaViewSet

router = DefaultRouter()
router.register(r'alpha', AlphaViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

最终效果示例

当你发起GET请求到/alpha/1/时,返回的JSON会是这样的(合并了Alpha和关联的Beta数据):

{
    "id": 1,
    "name": "测试Alpha",
    "description": "这是一个测试用的Alpha实例",
    "created_at": "2024-05-20T12:34:56Z",
    "betas": [
        {
            "id": 1,
            "beta_field1": "测试Beta1",
            "beta_field2": 100,
            "beta_field3": true
        },
        {
            "id": 2,
            "beta_field1": "测试Beta2",
            "beta_field2": 200,
            "beta_field3": false
        }
    ]
}

关键注意事项

  • 性能优化:永远记得用prefetch_related(反向外键/多对多)或select_related(正向外键),不然数据量大的时候会触发N+1查询,性能暴跌。
  • 生产环境规范:别用fields='__all__',明确指定需要返回的字段,避免泄露敏感数据。
  • 写入操作:如果需要在创建/更新Alpha时同时处理Beta数据,要在序列化器里重写create或update方法,手动处理关联数据的保存逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:34:48