Django1.11+DRF嵌套序列化器更新实现及PUT更新异常咨询
解决Django 1.11 + DRF中嵌套序列化器的更新问题
嘿,我来帮你搞定这两个问题!咱们一步一步来:
第一步:修复PUT触发新建的问题
你的EmployeeDetailView是基于APIView实现的,之所以触发新建逻辑,核心原因是序列化器初始化时没有传入要更新的实例,DRF默认走了create而不是update流程。
先把视图代码改成这样:
from django.shortcuts import get_object_or_404 from rest_framework.response import Response from rest_framework import status class EmployeeDetailView(APIView): permission_classes = [AllowAny] def get_object(self, pk): # 根据主键获取目标员工实例,不存在直接返回404 return get_object_or_404(Employee, pk=pk) def put(self, request, pk): # 先拿到要更新的员工对象 employee = self.get_object(pk) # 关键:把instance参数传给序列化器,明确告诉它要执行更新 serializer = EmployeeSerializer(employee, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
另外别忘了检查你的URL配置,必须包含pk参数,比如:
path('employees/<int:pk>/', EmployeeDetailView.as_view()),
第二步:解决User外键更新报错的问题
报错提示用户名已存在,是因为默认的嵌套序列化器会尝试新建一个User对象,而不是更新员工关联的现有User。咱们需要重写EmployeeSerializer的update方法,手动处理User实例的更新。
假设你的序列化器基础结构是这样的:
from rest_framework import serializers from .models import Employee, User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['username', 'email', 'first_name', 'last_name'] class EmployeeSerializer(serializers.ModelSerializer): user = UserSerializer() # 嵌套的User序列化器 class Meta: model = Employee fields = ['id', 'user', 'department', 'position']
现在修改EmployeeSerializer,添加自定义的update方法:
class EmployeeSerializer(serializers.ModelSerializer): user = UserSerializer() class Meta: model = Employee fields = ['id', 'user', 'department', 'position'] def update(self, instance, validated_data): # 先从验证后的数据中取出User相关字段 user_data = validated_data.pop('user') # 获取员工关联的现有User实例 user = instance.user # 逐个更新User字段(没传的字段保留原值) user.username = user_data.get('username', user.username) user.email = user_data.get('email', user.email) user.first_name = user_data.get('first_name', user.first_name) user.last_name = user_data.get('last_name', user.last_name) user.save() # 更新员工自身的字段 instance.department = validated_data.get('department', instance.department) instance.position = validated_data.get('position', instance.position) instance.save() return instance
额外小提示
- 如果User字段允许为空,记得加个判断:
if user_data:再执行更新逻辑 - 要是需要对User字段做额外验证,直接在
UserSerializer里定义就行,DRF会先验证嵌套序列化器,再执行update
内容的提问来源于stack exchange,提问作者Philip Mutua
相关产品推荐
相关产品推荐

