Django使用DRF序列化器校验完成的数据如何正确保存?
问题原因
首先你当前的代码会整体校验失败有两个核心原因:
- 你传入的是多条数据组成的列表,但初始化Serializer时没有加
many=True参数,Serializer默认按单条数据规则校验,直接报错 - 即使加了
many=True,DRF默认的批量序列化逻辑只要任意一条数据校验失败,整体就会返回False,且不会保留校验通过的条目
解决方案
方案1:逐条处理(适合数据量小的场景)
不需要修改原有Serializer定义,遍历每条数据单独校验、单独保存即可,代码如下:
success_items = [] error_items = [] for item in data: ser = CarSerializer(data=item) if ser.is_valid(): success_items.append(ser.save()) else: error_items.append({ "raw_data": item, "error_msg": ser.errors }) # 可自行后续处理error_items中的错误数据
缺点是每条数据单独执行插入SQL,数据量大时性能较差。
方案2:自定义支持跳过错误的批量序列化器(适合数据量大的场景)
通过自定义ListSerializer实现批量校验时自动跳过错误数据,最终批量插入有效数据,仅执行一次SQL,性能更高。
步骤1:自定义批量序列化器
from rest_framework import serializers class SkipErrorListSerializer(serializers.ListSerializer): def to_internal_value(self, data): valid_data = [] self.errors = [] for item in data: try: # 用子序列化器单独校验每条数据 valid_data.append(self.child.to_internal_value(item)) except serializers.ValidationError as e: # 记录错误信息,不抛出异常 self.errors.append(e.detail) return valid_data def is_valid(self, raise_exception=False): super().is_valid(raise_exception=False) # 只要存在有效数据就返回True,可根据业务需求调整判断逻辑 return len(self.validated_data) > 0
步骤2:修改CarSerializer关联自定义批量序列化器
class CarSerializer(serializers.ModelSerializer): class Meta: model = Car fields = ["name", "model", "serial number"] validators = [ UniqueTogetherValidator( queryset=Car.objects.all(), fields=["name", "model"] ) ] # 指定自定义的批量序列化类 list_serializer_class = SkipErrorListSerializer
步骤3:调用批量序列化逻辑
# 初始化时必须加many=True开启批量处理 ser = CarSerializer(data=data, many=True) if ser.is_valid(): # 批量插入所有校验通过的数据 ser.save() # 可通过ser.errors查看所有校验失败的错误信息
注意事项
默认的UniqueTogetherValidator只会校验提交数据和数据库已有数据的唯一性,不会校验本次批量提交数据内部的重复项,如果你需要避免同批次提交重复的name+model组合,可以在自定义ListSerializer的to_internal_value方法中新增同批次去重逻辑。
内容的提问来源于stack exchange,提问作者fabelx
相关产品推荐
相关产品推荐

