Django REST Framework中Patch请求仅更新CustomUser的detail字段报错
问题:Patch更新CustomUser的detail字段时被要求提供username
场景复现
自定义继承AbstractUser的CustomUser模型:
class CustomUser(AbstractUser): detail = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
前端通过Axios发送PATCH请求仅更新detail字段:
var formData = new FormData(); var status = { fileObj: this.fileObj.id } formData.append("detail", JSON.stringify(status)); axios.patch( `/api/customusers/3/`, formData ).then(function (response) { console.log("syncdata customuser is saved:", response); }).catch(function (response) { console.log("syncdata customuser failed:", response); });
后端ViewSet代码:
class CustomUserViewSet(viewsets.ModelViewSet): serializer_class = s.CustomUserSerializer queryset = m.CustomUser.objects.all() def update(self, request, *args, **kwargs): print("custom user update") print(request.data) # 输出:<QueryDict: {'detail': ['{"fileObj":19}']}> instance = self.get_object() serializer = self.get_serializer(instance, data=request.data) if serializer.is_valid(): self.perform_update(serializer) return Response(serializer.data) else: print(serializer.errors) # 输出:{'username': [ErrorDetail(string='This field is required.', code='required')]}
问题原因
- 你的
CustomUserSerializer继承自ModelSerializer时,会自动将AbstractUser中的username等核心字段标记为必填项。 - 默认调用
get_serializer未启用部分更新模式,序列化器会校验所有必填字段的存在性,哪怕是PATCH请求仅更新部分字段。
解决方案
方案一:视图中启用partial参数(最简方案)
初始化序列化器时添加partial=True参数,告诉序列化器允许部分字段更新,忽略未传递的必填字段:
def update(self, request, *args, **kwargs): print("custom user update") print(request.data) instance = self.get_object() # 添加partial=True启用部分更新 serializer = self.get_serializer(instance, data=request.data, partial=True) if serializer.is_valid(): self.perform_update(serializer) return Response(serializer.data) else: print(serializer.errors)
方案二:序列化器中动态调整字段必填性
如果需要全局控制更新时的字段规则,可修改序列化器,在更新操作(存在instance)时将username等字段设为非必填:
# 假设你的CustomUserSerializer定义如下 class CustomUserSerializer(serializers.ModelSerializer): class Meta: model = CustomUser # 列出需要暴露的字段,包含AbstractUser字段和自定义字段 fields = ('id', 'username', 'email', 'detail', 'created_at', 'updated_at') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 当存在instance时(更新操作),调整必填字段 if self.instance is not None: # 将username、email等字段设为非必填 for field in ['username', 'email']: if field in self.fields: self.fields[field].required = False
额外提示
前端用FormData传递JSON格式的detail字段是可行的,后端序列化器会自动将JSON字符串解析为字典(对应模型的JSONField),无需额外处理。
内容的提问来源于stack exchange,提问作者whitebear
相关产品推荐
相关产品推荐

