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

如何在Django REST Framework中实现嵌套序列化并优化性能?

解决DRF嵌套序列化器问题及Prefetch性能优化

一、修复嵌套序列化器输出问题

先确保模型关联配置正确,再按照DRF规则编写嵌套序列化器。

1. 模型关联检查(基于常见业务场景)

假设你的模型结构如下,核心是配置related_name作为关联查询的属性名:

from django.db import models

class Workshop(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField()
    # 其他自定义字段

class WorkshopMaterial(models.Model):
    workshop = models.ForeignKey(Workshop, on_delete=models.CASCADE, related_name='materials')
    name = models.CharField(max_length=100)
    file_url = models.URLField()
    # 其他自定义字段

2. 序列化器正确嵌套写法

在serializers.py中,将子序列化器作为字段嵌套到父序列化器中:

from rest_framework import serializers
from .models import Workshop, WorkshopMaterial

class WorkshopMaterialsSerializer(serializers.ModelSerializer):
    class Meta:
        model = WorkshopMaterial
        fields = ['id', 'name', 'file_url']  # 按需指定返回字段

class WorkshopSerializer(serializers.ModelSerializer):
    # 用模型中定义的related_name作为字段名,开启多实例模式
    materials = WorkshopMaterialsSerializer(many=True, read_only=True)

    class Meta:
        model = Workshop
        fields = ['id', 'title', 'description', 'materials']  # 包含嵌套字段

注意:如果需要支持写入(创建/更新时提交物料数据),需要额外重写序列化器的create和update方法。

3. 视图层配置

在views.py中确保查询集正确返回Workshop实例:

from rest_framework import viewsets
from .models import Workshop
from .serializers import WorkshopSerializer

class WorkshopViewSet(viewsets.ModelViewSet):
    queryset = Workshop.objects.all()
    serializer_class = WorkshopSerializer

4. 常见问题排查

  • 嵌套字段不显示:检查模型的related_name是否和序列化器中的字段名完全一致
  • 出现AttributeError:确认Workshop实例存在materials属性(由related_name定义)
  • 返回空数组:检查该Workshop是否有对应的WorkshopMaterial关联记录

二、使用Prefetch优化查询性能

默认嵌套序列化会触发N+1查询问题(每个Workshop单独查询一次物料),Prefetch可以批量获取关联数据,减少数据库查询次数。

1. 基础Prefetch用法

修改views.py中的查询集:

from django.db.models import Prefetch
from .models import Workshop, WorkshopMaterial

class WorkshopViewSet(viewsets.ModelViewSet):
    # 预取所有关联的WorkshopMaterial
    queryset = Workshop.objects.prefetch_related(
        Prefetch('materials', queryset=WorkshopMaterial.objects.all())
    )
    serializer_class = WorkshopSerializer

2. 带过滤条件的Prefetch

如果只需要预取特定条件的物料(比如已发布的物料),可以在Prefetch中指定过滤后的查询集:

queryset = Workshop.objects.prefetch_related(
    Prefetch(
        'materials',
        queryset=WorkshopMaterial.objects.filter(is_published=True),
        to_attr='published_materials'  # 可选:将结果存到自定义属性名
    )
)

若使用to_attr,需同步修改序列化器中的字段名:

class WorkshopSerializer(serializers.ModelSerializer):
    published_materials = WorkshopMaterialsSerializer(many=True, read_only=True)
    # ...其他配置

3. 优化效果对比

  • 优化前:1次Workshop列表查询 + N次物料查询 = N+1次数据库请求
  • 优化后:仅2次请求(1次查Workshop,1次批量查所有关联物料)

三、输出对比示例

当前错误输出(无嵌套物料):

[
  {
    "id": 1,
    "title": "Python入门 Workshop",
    "description": "基础语法教学"
  }
]

期望正确输出(包含嵌套物料列表):

[
  {
    "id": 1,
    "title": "Python入门 Workshop",
    "description": "基础语法教学",
    "materials": [
      {
        "id": 1,
        "name": "Python语法手册",
        "file_url": "http://example.com/manual.pdf"
      },
      {
        "id": 2,
        "name": "练习代码包",
        "file_url": "http://example.com/code.zip"
      }
    ]
  }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:59:53