Django APITestCase测试缺失必填布尔字段未触发400校验问题
问题原因
这个问题的核心差异来源于请求数据的解析逻辑不同:
- 你通过Insomnia发起的是
application/json类型的请求,Django不会对JSON格式的请求体做自动字段补全,未传递的in_possession字段会原样交给DRF处理,DRF检测到必填字段缺失就会返回400错误。 - 你在单元测试中默认使用的是
application/x-www-form-urlencoded格式提交数据,Django为了适配HTML表单的特性(未勾选的checkbox不会随表单提交),会自动将模型定义中布尔类型的缺失字段填充为False,这个操作发生在DRF校验逻辑执行之前,因此DRF拿到的请求数据里已经存在in_possession=False,自然不会触发必填校验,直接返回201创建成功。
解决方案
根据你的使用场景可以选择对应解决方法:
- 方案1:单元测试显式指定JSON格式提交(推荐,适配绝大多数前后端分离接口场景)
调用测试客户端的POST方法时添加format='json'参数,禁用Django的表单字段自动填充逻辑,让DRF可以正常识别缺失字段:
示例代码:# 错误写法 response = self.client.post('/api/status/', data={'other_field': 'test'}) # 正确写法 response = self.client.post('/api/status/', data={'other_field': 'test'}, format='json') - 方案2:Serializer显式声明字段必填属性
如果需要兼容表单提交场景,可以在ModelSerializer中手动覆写字段配置,强制开启必填校验:
示例代码:class StatusSerializer(serializers.ModelSerializer): # 显式指定字段必填,覆盖ModelSerializer自动生成的默认配置 in_possession = serializers.BooleanField(required=True) class Meta: model = Status fields = '__all__' - 方案3:自定义校验逻辑检测字段是否显式传递
如果你需要严格校验字段是否被主动传递,忽略框架自动填充逻辑,可以在Serializer的校验方法中判断初始请求数据是否包含对应字段:
示例代码:class StatusSerializer(serializers.ModelSerializer): class Meta: model = Status fields = '__all__' def validate(self, attrs): if 'in_possession' not in self.initial_data: raise serializers.ValidationError({'in_possession': '该字段为必填项'}) return attrs
内容的提问来源于stack exchange,提问作者nck
相关产品推荐
相关产品推荐

