Drf Writable nested serializers "This field is required."
Here is the code: 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
I'm try create test question with few option of answers like this:
data = {
"lesson": 2,
"question": "This is our first question?",
"options": [
{
"option": "Option 1",
"correct": True
},
{
"option": "Option 2 ",
"correct": False
},
{
"option": "Option 3",
"correct": True
}
]
}
But in postman and in the TestCase I've got:
{
"options": [
"This field is required."
]
}
What is the problem of validation? Documentation here https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers Thanks.
Although I believe required=True
inside OptionSerializer(many=True,required=True)
should fix your issue if your json for OptionSerializer
is correct else the following solution might sort out your problem
class QuestionSerializer(serializers.ModelSerializer):
options = serializers.SerializerMethodField()
class Meta:
model = Question
fields = ('lesson', 'question', 'options')
def get_options(self, obj):
options = Option.objects.filter(question=obj)
serializer = OptionSerializer(options, many=True)
return serializer.data
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
It does work perfectly in my testing. Just note your JSON object, you used True / False as Python boolean varible not JSONs: (Tested both with postman and DRF Browsable API)
data = {
"lesson": 2,
"question": "This is our first question?",
"options": [
{
"option": "Option 1",
"correct": true
},
{
"option": "Option 2 ",
"correct": false
},
{
"option": "Option 3",
"correct": true
}
]
}