You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:47:56