I am getting a JSON input with the fields description
and choices
for a Question
model. The Choice
model also has a foreign key field pointing to Question
with a related name of choices
. However, in the JSON, the Choice
will come without the question_id
field, in order to be assigned after the creation of the Question
I am getting all kind of errors when trying to create a Question
and then assigning all incoming to it. Searched a lot for the error Direct assignment to the forward side
and didn't found anything that solves my problem
CreateChoiceSerializer
does not takes any question_id
to be created, I solve the problem of assigning the Question
by using the context
field
I can't change the related name and the JSON input fields, if this was a possibility I'd have already done it
class CreateQuestionSerializer(serializers.ModelSerializer):
description = serializers.CharField(max_length=1024, allow_blank=False, required=True)
choices = CreateChoiceSerializer(many=True, required=True)
def create(self, validated_data):
choices = validated_data.pop('choices')
question = Question.objects.create(**validated_data)
choices_serializer = CreateChoiceSerializer(data=choices, many=True, context={'question': question})
if choices_serializer.is_valid():
choices_serializer.save()
return question
class CreateChoiceSerializer(serializers.ModelSerializer):
description = serializers.CharField(max_length=1024, allow_blank=False, required=True, allow_null=False)
class Meta:
model = Choice
fields = ['description']
def create(self, validated_data):
question = self.context.get('question')
choice = Choice.objects.create(question=question, **validated_data)
return choice
EDIT:
Models:
class Question(models.Model):
id = models.AutoField(primary_key=True)
description = models.CharField(max_length=1024, blank=False, null=False)
class Choice(models.Model):
id = models.AutoField(primary_key=True)
question = models.ForeignKey(Question,
related_name='choices',
on_delete=models.PROTECT)
description = models.CharField(max_length=1024, blank=False, null=False)
Whenever I set the CreateChoiceSerializer
field required
to false, Django raises an error Direct assignment to the reverse side of a related set is prohibited
If I were you, I use these serializers to create questions with related choices.
class CreateChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = "__all__"
class CreateQuestionSerializer(serializers.ModelSerializer):
description = serializers.CharField(max_length=1024, allow_blank=False, required=True)
choices = CreateChoiceSerializer(many=True, required=True)
def create(self, validated_data):
choices = validated_data.pop('choices')
question = Question.objects.create(**validated_data)
choices_model = []
for choice in choices:
choices_model.append(Choice(question_id=question.id, **choice))
Choice.objects.bulk_create(choices_model)
return question
If you call the function QuestionSerializer.is_valid
, it will validate the choices' value too. So it doesn't need to pass the values to ChoiceSerializer
and validate them again in function QuestionSerializer.create
.
I use bulk_create
function to insert all the choices at once.
suggestion: you can use atomic transaction in the function create
to be sure that the question and related choices are always created safely, not part of them.
note: the script that I wrote may not exactly fit your code. because I don't know what your models are.