使用prefetch_related实现DRF嵌套序列化失败,请求排查
我尝试在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']
请问哪里出错了?如何解决?
解决方案
你的核心问题是序列化器字段名与模型关联名称不匹配:
在
CourseEnroll模型中,course外键的related_name设置为course_enroll,这意味着从Course实例访问关联的CourseEnroll数据时,必须使用course.course_enroll。但你的CourseSerializer里用了student_enrolled作为字段名,DRF无法找到对应关联数据,导致嵌套序列化失效。另外,当前
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
相关产品推荐
相关产品推荐

