DRF通过AJAX更新数据报400字段必填错误,可浏览API正常是什么原因
错误原因
1. shipment字段必填报错根源
- 你在
ProductSerializer中显式声明了shipment = ShipmentSerializer(),默认嵌套序列化器是必填且接收对象结构的,不是接收单个 shipment id 数字。 - 你第一次请求的payload是
shipment=4的form格式,DRF解析后拿到的shipment是单个数字,不符合嵌套序列化器的结构校验,直接判定字段无效/缺失,抛出必填错误。 - DRF可浏览API正常是因为你在表单里填的是嵌套结构的shipment数据,符合序列化器校验规则。
2. JSON parse error报错根源
- 你的AJAX配置里指定了
contentType: "application/json",但直接把JS对象{"shipment": shipment[0]}传给了data参数,jQuery默认会把JS对象序列化为x-www-form-urlencoded格式的字符串(也就是shipment=4这种),不是JSON格式。 - DRF按照JSON格式解析请求体的时候,拿到的是form格式的字符串,完全不符合JSON语法,直接抛出解析错误。
修复方案
根据你的业务需求二选一即可:
方案1:保留嵌套序列化器(接口返回shipment完整信息)
首先修改AJAX代码,把请求体转成符合要求的JSON格式:
$.ajax({ url: `api/products/${serial}/`, dataType: "json", contentType: "application/json", type: "PUT", // 转成JSON字符串,且shipment按嵌套对象结构传值 data: JSON.stringify({"shipment": {"id": shipment[0]}}), headers: {"X-CSRFTOKEN": csrf_token }, success: function () {window.location = "?msg=ok";}, error: function () {window.location = "?msg=error";} });
同时修正序列化器update方法的参数错误(update第二个参数是校验后的数据,不是请求对象):
def update(self, instance, validated_data): shipment_data = validated_data.pop('shipment') instance.shipment = Shipment.objects.get(id=shipment_data["id"]) instance.save() return instance
方案2:不需要嵌套返回,直接传shipment id即可
把序列化器里的嵌套声明去掉,用DRF原生外键逻辑处理,更简洁:
class ProductSerializer(serializers.ModelSerializer): # 删掉自定义的shipment嵌套序列化器声明 class Meta: model = Product fields = ["serial", "shipment",] lookup_field = "serial" read_only_fields = ["serial",]
对应AJAX代码只需要把请求体转成JSON即可:
$.ajax({ url: `api/products/${serial}/`, dataType: "json", contentType: "application/json", type: "PUT", data: JSON.stringify({"shipment": shipment[0]}), headers: {"X-CSRFTOKEN": csrf_token }, success: function () {window.location = "?msg=ok";}, error: function () {window.location = "?msg=error";} });
该方案不需要自定义update方法,DRF会自动完成外键赋值逻辑。
内容的提问来源于stack exchange,提问作者xtlc
相关产品推荐
相关产品推荐

