DRF可写嵌套序列化器报错‘This field is required.’求排查
DRF可写嵌套序列化器出现"options字段必填"错误的原因及解决方法
在使用Django REST Framework(DRF)创建带选项的测试试题时,提交了包含options数组的JSON数据,但在Postman和测试用例中均收到验证错误,提示options字段必填。
提交的数据:
{ "lesson": 2, "question": "This is our first question?", "options": [ { "option": "Option 1", "correct": True }, { "option": "Option 2 ", "correct": False }, { "option": "Option 3", "correct": True } ] }
错误响应:
{ "options": [ "This field is required." ] }
相关代码:
models.py
class Question(models.Model): lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, related_name='questions') question = models.CharField('lesson name', max_length=120) class Option(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='options') option = models.CharField('test option', max_length=100) correct = models.BooleanField(default=False)
views.py
class QuestionAPIView(generics.CreateAPIView): queryset = Question.objects.all() serializer_class = QuestionSerializer
serializers.py
class OptionSerializer(serializers.ModelSerializer): class Meta: model = Option fields = ('option', 'correct') class QuestionSerializer(serializers.ModelSerializer): options = OptionSerializer(many=True) class Meta: model = Question fields = ('lesson', 'question', 'options') def create(self, validated_data): options_data = validated_data.pop('options') question = Question.objects.create(**validated_data) for option_data in options_data: Option.objects.create(question=question, **option_data) return question
错误原因
错误的核心是DRF中嵌套序列化器字段默认是只读的:
- 在
QuestionSerializer中,options = OptionSerializer(many=True)这个嵌套字段默认标记为read_only=True,DRF处理输入数据(反序列化)时会忽略提交的options字段,不会将其解析到validated_data中。 - 同时该字段的
required属性默认是True,DRF会验证该字段是否存在,但因为它是只读的,DRF无法识别到你提交的options数据,因此判定该字段缺失,返回必填错误。
解决方案
修改QuestionSerializer中的options字段定义,显式设置read_only=False,让DRF允许该字段接收输入数据:
class QuestionSerializer(serializers.ModelSerializer): # 添加read_only=False,允许嵌套字段接收输入 options = OptionSerializer(many=True, read_only=False) class Meta: model = Question fields = ('lesson', 'question', 'options') def create(self, validated_data): options_data = validated_data.pop('options') question = Question.objects.create(**validated_data) for option_data in options_data: Option.objects.create(question=question, **option_data) return question
如果希望options字段只在创建/更新时接收输入,而不在返回的序列化数据中展示,可以改为设置write_only=True:
options = OptionSerializer(many=True, write_only=True)
修改后,DRF会正确解析提交的options数据,create方法也能正常取出options_data创建关联的Option实例。
内容的提问来源于stack exchange,提问作者Anna Berezko
相关产品推荐
相关产品推荐

