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

使用prefetch_related实现DRF嵌套序列化失败,请求排查

问题:Django Rest Framework中使用prefetch_related实现嵌套序列化失败

我尝试在DRF中用prefetch_related实现嵌套序列化,但没有成功,以下是我的代码:

models.py

from django.db import models


class Student(models.Model):
    phone = models.IntegerField(null=True)
    birth_date = models.DateField(null=True)
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name="student")


class Course(models.Model):
    title = models.CharField(max_length=100, blank=True, default='')


class CourseEnroll(models.Model):
    course = models.ForeignKey(Course, on_delete=models.PROTECT, related_name='course_enroll')
    student = models.ForeignKey(Student, on_delete=models.PROTECT, related_name='student_enroll')

views.py

from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet

from quiz.models import Course
from quiz.serializers import CourseSerializer


class CourseViewSet(mixins.CreateModelMixin,
                    mixins.ListModelMixin,
                    mixins.RetrieveModelMixin,
                    GenericViewSet):

    def get_queryset(self):
        queryset = Course.objects.prefetch_related("course_enroll").all()
        return queryset
    serializer_class = CourseSerializer

serializers.py

from rest_framework import serializers

from quiz.models import Course, CourseEnroll


class CourseEnrollSerializer(serializers.ModelSerializer):
    class Meta:
        model = CourseEnroll
        fields = ['id']


class CourseSerializer(serializers.ModelSerializer):
    student_enrolled = CourseEnrollSerializer(many=True, read_only=True)

    class Meta:
        model = Course
        fields = ['id', 'title', 'student_enrolled']

请问哪里出错了?如何解决?


解决方案

你的核心问题是序列化器字段名与模型关联名称不匹配:

  1. 在CourseEnroll模型中,course外键的related_name设置为course_enroll,这意味着从Course实例访问关联的CourseEnroll数据时,必须使用course.course_enroll。但你的CourseSerializer里用了student_enrolled作为字段名,DRF无法找到对应关联数据,导致嵌套序列化失效。

  2. 另外,当前CourseEnrollSerializer仅返回id,如果需要展示学生的具体信息,还需嵌套Student序列化器。

修改后的代码:

方案1:仅修复字段匹配(返回CourseEnroll的id)

# serializers.py
from rest_framework import serializers

from quiz.models import Course, CourseEnroll


class CourseEnrollSerializer(serializers.ModelSerializer):
    class Meta:
        model = CourseEnroll
        fields = ['id']


class CourseSerializer(serializers.ModelSerializer):
    # 将字段名改为与related_name一致的course_enroll
    course_enroll = CourseEnrollSerializer(many=True, read_only=True)

    class Meta:
        model = Course
        fields = ['id', 'title', 'course_enroll']

方案2:显示学生详细信息(嵌套Student序列化)

# serializers.py
from rest_framework import serializers

from quiz.models import Course, CourseEnroll, Student


class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ['id', 'phone', 'birth_date']


class CourseEnrollSerializer(serializers.ModelSerializer):
    # 嵌套Student序列化器,展示学生信息
    student = StudentSerializer(read_only=True)
    
    class Meta:
        model = CourseEnroll
        fields = ['id', 'student']


class CourseSerializer(serializers.ModelSerializer):
    course_enroll = CourseEnrollSerializer(many=True, read_only=True)

    class Meta:
        model = Course
        fields = ['id', 'title', 'course_enroll']

优化查询(可选)

如果使用方案2,为避免N+1查询问题,可以在get_queryset中进一步预取关联的Student数据:

# views.py
from django.db.models import Prefetch

def get_queryset(self):
    queryset = Course.objects.prefetch_related(
        Prefetch('course_enroll', queryset=CourseEnroll.objects.select_related('student'))
    ).all()
    return queryset

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:42:05