I have the following models in my django rest framework app:
class Question(models.Model):
class Type(models.TextChoices):
TEXT = 'text', 'text question'
RADIO = 'radio', 'choosing one option quesiton'
CHOICE = 'check', 'choosing multiple options question'
type = models.CharField(max_length=5, choices=Type.choices)
title = models.CharField()
description = models.TextField(blank=True, default='')
def __str__(self) -> str:
return f'{self.type}: {self.title}'
class TextQuestion(Question):
answer = models.CharField()
class RadioQuestion(Question):
variants = fields.ArrayField(models.CharField())
answer = models.CharField()
class ChoiceQuestion(Question):
variants = fields.ArrayField(models.CharField())
answers = fields.ArrayField(models.CharField())
class Test(models.Model):
name = models.CharField()
creator = models.ForeignKey(User, on_delete=models.CASCADE)
questions = models.ManyToManyField(Question)```
I want to write serializer for test serialization, but I dont know how to serialize questions field. Because I have different serializer for every question type: What should I do? Maybe it`s better to reorganize my models somehow?
I already writed serializers for all question types:
class TextQuestionSerializer(serializers.ModelSerializer):
class Meta:
model = TextQuestion
fields = '__all__'
class RadioQuestionSerializer(serializers.ModelSerializer):
class Meta:
model = RadioQuestion
fields = '__all__'
class ChoiceQuestionSerializer(serializers.ModelSerializer):
class Meta:
model = ChoiceQuestion
fields = '__all__'
I thought about using serializer.SerializerMethodField()
but it this doesnt work with many=True
I had this issue like this, you can use serializer.SerializerMethodField() and write a serializer for test with isinstance(). For example:
class TestSerializer(serializers.ModelSerializer):
questions = serializers.SerializerMethodField()
class Meta:
model = Test
fields = ['id', 'name', 'creator', 'questions']
def get_questions(self, obj):
questions = obj.questions.all()
serialized_questions = []
for question in questions:
if isinstance(question, TextQuestion):
serialized_question = TextQuestionSerializer(question).data
#continiue other tasks
serialized_questions.append(serialized_question)
return serialized_questions ##read_only
class TestSerializer(serializers.ModelSerializer):
questions = serializers.ListField(child=serializers.DictField())
class Meta:
model = Test
fields = '__all__'
def create(self, validated_data):
questions_data = validated_data.pop('questions')
test = Test.objects.create(**validated_data)
for question_data in questions_data:
question_type = question_data.pop('type')
if question_type == 'text':
TextQuestion.objects.create(test=test, **question_data)
#continiue other tasks
return test
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.save()
questions_data = validated_data.get('questions', [])
for question_data in questions_data:
question_type = question_data.pop('type')
question_id = question_data.pop('id', None)
if question_id:
if question_type == 'text':
question = TextQuestion.objects.get(id=question_id)
#continiue other tasks
for key, value in question_data.items():
setattr(question, key, value)
question.save()
return instance
You can check this and if it doesn't work let me know:)