React axios PATCH请求带Authorization仍报401及Django字段覆盖问题
问题1:最初401错误的原因
最早的PATCH请求你把headers参数写到了请求体(axios.patch第二个参数)的位置,axios没有正确读取到Authorization头,调整参数顺序(把配置项放到第三个参数)后就修复了这个问题。
问题2:数据不更新、传列表报错的原因
- 你在发送FormData的时候硬指定了
Content-Type: application/json,二者完全冲突:FormData对应的Content-Type是multipart/form-data,你手动写死JSON类型会导致Django无法正确解析请求体,拿不到你传的参数。把这个手动设置的Content-Type头删掉就行,axios发送FormData的时候会自动带上正确的Content-Type。 - 你的序列化器配置错误:你定义的
groups字段设置了read_only=True,序列化器不会处理前端传来的groups相关参数,自然不会更新对应字段。而且如果你的UserGroup模型里group是单外键字段,传列表肯定会报类型错误,如果你需要一个用户对应多个用户组,应该把模型字段改成ManyToManyField类型。 - PATCH请求是更新操作,你的视图里成功后返回201状态码不符合规范,201是创建资源的返回码,更新成功应该返回200。
问题3:更新覆盖原有组的解决方案
方案1:前端拼接+后端适配(最小改动)
- 先确认模型字段为多对多类型:
# models.py class UserGroup(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) groups = models.ManyToManyField(Group, related_name="user_groups") # 其他自定义字段
- 修改序列化器,让groups支持读写主键列表:
class UserGroupSerializer(serializers.ModelSerializer): groups = GroupSerializer(many=True, read_only=True) # 新增可写的主键字段,用于接收前端传的组ID列表 group_ids = serializers.PrimaryKeyRelatedField( many=True, queryset=Group.objects.all(), write_only=True, source="groups" ) class Meta: model = UserGroup fields = '__all__'
- 前端修改请求逻辑:不需要用FormData,直接传JSON即可,拿到旧的组ID列表追加新ID后传给
group_ids字段:
handleJoin = (e, group) => { e.preventDefault(); const token = `JWT ${localStorage.getItem('token')}`; axios.get('http://127.0.0.1:8000/core/current_user/', { headers: { Authorization: token } }) .then((user) => { return axios.get(`http://127.0.0.1:8000/core/usergroup/${user.data.id}/`, { headers: { Authorization: token } }) .then((usergroup) => { // 拼接新旧组ID const groupIds = usergroup.data.groups.map(g => g.id); groupIds.push(group.id); return axios.patch( `http://127.0.0.1:8000/core/usergroup/${user.data.id}/`, { group_ids: groupIds }, { headers: { Authorization: token } } ) }) }) .then((res) => { console.log(res.data); }) .catch((err) => { console.log(err); }); }
方案2:后端直接实现追加逻辑(更安全,避免并发覆盖)
直接在视图的patch方法里处理追加逻辑,不需要前端传全量列表,只需要传要新增的组ID即可,从根源避免覆盖问题:
# views.py class UserGroupDetail(APIView): def patch(self, request, pk): usergroup = UserGroup.objects.get(pk=pk) # 只取要新增的组ID add_group_id = request.data.get("add_group_id") if add_group_id: # 多对多字段调用add方法追加,不会覆盖原有数据 usergroup.groups.add(add_group_id) return Response(UserGroupSerializer(usergroup).data, status=status.HTTP_200_OK) # 保留原有其他字段的更新逻辑 serializer = UserGroupSerializer(instance=usergroup, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
前端不需要再先请求一次现有组列表,直接传add_group_id参数即可。
内容的提问来源于stack exchange,提问作者Tochy Egeonu
相关产品推荐
相关产品推荐

