DRF ChoiceField无效值未触发验证错误,如何实现校验报错?
问题
提交错误的ChoiceField选项值时,Serializer仍会保存数据,但Django admin中该字段显示为空;提交正确选项值时数据正常保存且admin显示正确。希望在用户提交错误数据时返回验证错误,已尝试配置subject = serializers.ChoiceField(choices=School.SUBJECT),但觉得遍历元组校验不规范也不高效,寻求解决方案。
相关代码
视图集代码
class SchoolViewSet(viewsets.ModelViewSet): queryset = School.objects.all() serializer_class = SchoolSerializer def create(self, request): serializer = SchoolSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
模型代码
class School(models.Model): SUBJECT = ( ('Math', 'Mathematic'), ('Eng', 'English'), ('Cesolved', 'Chemistry'), ) name = models.CharField(blank=False, max_length=50) subject = models.CharField(choices=SUBJECT, max_length=15, blank=False) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) def __str__(self): return str(f'{self.name} is {self.subject}')
序列化器代码
class SchoolSerializer(serializers.ModelSerializer): subject = serializers.ChoiceField(choices=School.SUBJECT) def validate(self, data): name = data["name"] if (5 > len(name)): raise serializers.ValidationError({"IError": "Invalid name"}) return data class Meta: model = School fields = "__all__"
解决方法
方案1:利用模型自动映射校验规则
不需要手动指定serializers.ChoiceField,ModelSerializer会自动读取模型字段的choices配置生成校验逻辑。删除序列化器中手动定义的subject字段即可:
class SchoolSerializer(serializers.ModelSerializer): def validate(self, data): name = data["name"] if len(name) < 5: raise serializers.ValidationError({"IError": "Invalid name"}) return data class Meta: model = School fields = "__all__"
修改后,提交错误选项值时,序列化器会直接返回{"subject": ["\"错误值\" is not a valid choice."]}的验证错误,无需手动处理元组遍历。
方案2:手动指定ChoiceField时开启严格校验
如果坚持手动定义字段,可添加strict=True参数(DRF 3.10+支持),强制校验输入值必须为合法选项:
class SchoolSerializer(serializers.ModelSerializer): subject = serializers.ChoiceField(choices=School.SUBJECT, strict=True) def validate(self, data): name = data["name"] if len(name) < 5: raise serializers.ValidationError({"IError": "Invalid name"}) return data class Meta: model = School fields = "__all__"
strict=True会让ChoiceField拒绝所有非选项值,直接触发验证错误,避免错误值被转为空值存入数据库。
问题根源说明
DRF的ChoiceField默认是宽松模式,输入值不在选项中时会转为None,但你的模型subject字段设置了blank=False却未开启序列化器严格校验,导致错误值被转为空字符串存入数据库,最终admin显示为空。上述两种方案都能从序列化器层面拦截非法值,返回明确的验证错误。
内容的提问来源于stack exchange,提问作者rafaelHTML
相关产品推荐
相关产品推荐

