如何在Django Rest Framework中为外键关联模型序列化器添加额外字段
实现方案
你需要的功能有两种极简实现方式,分别对应「返回部门信息时附带教师列表」和「单独查询指定部门教师列表」两种场景,修改如下:
方案1:在部门序列化器中直接关联教师(返回部门信息时附带教师列表)
第一步:修改模型增加反向关系别名(可选,可读性更高)
修改models.py中Teacher的外键字段,增加related_name定义后续调用的反向关联名:
class Teacher(models.Model): name = models.CharField(max_length=300) # 增加related_name参数,后续可以通过department.teachers直接取关联教师 department = models.ForeignKey(Department, on_delete=models.CASCADE, related_name="teachers") tenure = models.BooleanField()
如果不想修改模型,也可以直接用Django默认生成的反向关联名teacher_set。
第二步:调整序列化器配置
先补全缺失的TeacherSerializer,再修改DepartmentSerializer直接关联教师数据:
# 先定义教师序列化器,根据需求返回字段 class TeacherSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Teacher fields = ['url', 'name', 'tenure'] class DepartmentSerializer(serializers.HyperlinkedModelSerializer): # 直接关联教师序列化器,many=True表示一对多关系 # 如果只需要返回教师姓名,也可以替换为 teachers = serializers.StringRelatedField(many=True) # 如果只需要返回教师ID,替换为 teachers = serializers.PrimaryKeyRelatedField(many=True, read_only=True) teachers = TeacherSerializer(many=True, read_only=True) class Meta: model = Department fields = ['url', 'name', 'teachers']
第三步:优化查询避免N+1性能问题
修改views.py中DepartmentViewSet的查询集,提前预加载关联的教师数据:
class DepartmentViewSet(viewsets.ModelViewSet): # 增加prefetch_related预加载关联教师 queryset = Department.objects.all().prefetch_related('teachers') serializer_class = DepartmentSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly]
方案2:单独做部门教师查询接口(无需修改部门序列化器,更灵活)
如果不需要每次拉取部门信息都附带教师列表,可以单独新增接口,访问/api/departments/{部门ID}/teachers/即可直接获取对应部门的教师列表:
from rest_framework.decorators import action from rest_framework.response import Response class DepartmentViewSet(viewsets.ModelViewSet): queryset = Department.objects.all() serializer_class = DepartmentSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] # 新增detail路由,对应单个部门的教师查询 @action(detail=True, methods=['get']) def teachers(self, request, pk=None): department = self.get_object() # 用模型反向关系取关联教师 teachers = department.teachers.all() serializer = TeacherSerializer(teachers, many=True, context={'request': request}) return Response(serializer.data)
原代码问题说明
serializers.DjangoModelField不适用于关联数据查询,该字段是用于序列化模型字段的元属性,不是用来拉取关联业务数据的- 类定义阶段无法访问
self实例,你写的Teacher.objects.filter(department=self.department)在类加载时就会执行,此时还没有请求对应的部门实例,必然报错
内容的提问来源于stack exchange,提问作者KSWebDev1
相关产品推荐
相关产品推荐

