使用DRF Serializer填充Django模型字段时出现非空错误排查
DRF序列化时出现"This field may not be null"错误的排查与解决
尝试通过DRF Serializer将数据填充到Django模型的DecimalField和CharField字段时,触发了奇怪的"This field may not be null"错误,以下是相关代码及报错信息:
模型定义
class Product(BaseModel): product = models.CharField(max_length=255) recommended_action = models.CharField(max_length=255) recommended_action_value = models.DecimalField(max_digits=12, decimal_places=8) recommended_price = models.DecimalField(max_digits=12, decimal_places=8) rrp = models.DecimalField(max_digits=12, decimal_places=8) iam_price = models.DecimalField(max_digits=12, decimal_places=8) iam_index = models.DecimalField(max_digits=12, decimal_places=8) factor = models.DecimalField(max_digits=12, decimal_places=8) avg_in_stock = models.DecimalField( null=True, blank=True, max_digits=12, decimal_places=8 )
序列化器定义
class ProductSerializer(serializers.ModelSerializer): class Meta: model = models.Product fields = "__all__"
视图代码
@api_view(['POST']) def migrate_data(request, *args, **kwargs): if request.method == "POST": data = json.loads(request.body) product_serialized_data = serializers.ProductSerializer( data=data, many=True, context={"request": request}, ) if not product_serialized_data.is_valid(): print(product_serialized_data.errors) product_serialized_data.save() return Response(data={"detail": "Success"})
请求数据
{ "product": "DE_Ford_2095160", "recommended_action": "increase", "recommended_action_value": 0.0315553, "recommended_price": 14.5862, "rrp": 14.14, "iam_price": 6.56898, "iam_index": 0.464567, "factor": 2.15254, "avg_in_stock": 1 }
报错信息
[ { 'recommended_action': [ErrorDetail(string='This field may not be null.', code='null')], 'recommended_action_value': [ErrorDetail(string='This field may not be null.', code='null')], 'recommended_price': [ErrorDetail(string='This field may not be null.', code='null')], 'rrp': [ErrorDetail(string='This field may not be null.', code='null')], 'iam_index': [ErrorDetail(string='This field may not be null.', code='null')], 'factor': [ErrorDetail(string='This field may not be null.', code='null')] } ]
问题原因及修复方案
1. many=True 与请求数据格式不匹配
序列化器中设置了many=True,表示要处理数组格式的批量数据,但实际请求发送的是单个对象。DRF会错误地将单个对象的每个键解析为数组元素,导致所有字段被识别为null。
修复:
- 如果是单条数据,直接移除
many=True参数; - 如果需要批量处理,请求数据需改为数组格式,示例:
[ { "product": "DE_Ford_2095160", // 其他字段... } ]
2. 不必要的json.loads(request.body)
DRF的request.data已经自动完成了请求体的解析工作,不需要手动调用json.loads。手动解析可能因请求头(如Content-Type)处理逻辑冲突导致数据异常,直接使用request.data即可。
3. 视图逻辑漏洞
product_serialized_data.save()写在了if request.method == "POST"代码块外部,非POST请求会直接触发变量未定义错误;- 即使验证不通过,代码依然执行
save(),会导致无效数据尝试入库。
修复后的视图代码:
from rest_framework import status @api_view(['POST']) def migrate_data(request, *args, **kwargs): product_serialized_data = serializers.ProductSerializer( data=request.data, # 根据实际需求决定是否保留many=True # many=True, context={"request": request}, ) if product_serialized_data.is_valid(): product_serialized_data.save() return Response(data={"detail": "Success"}) # 验证失败时返回错误信息 return Response(product_serialized_data.errors, status=status.HTTP_400_BAD_REQUEST)
4. 可选:Decimal字段精度保障
如果请求中传递的是浮点数,存入DecimalField可能存在精度丢失风险,可在序列化器中显式指定字段类型,确保转换逻辑正确:
class ProductSerializer(serializers.ModelSerializer): recommended_action_value = serializers.DecimalField(max_digits=12, decimal_places=8) recommended_price = serializers.DecimalField(max_digits=12, decimal_places=8) # 其他Decimal字段同理 class Meta: model = models.Product fields = "__all__"
内容的提问来源于stack exchange,提问作者Khubaib Khawar
相关产品推荐
相关产品推荐

