Django Rest Framework - Как создать валидацию вложенных объектов в сериализаторах
Я изучаю drf и хотел перенести часть логики создания в сериализатор, но застрял.
У меня есть следующие модели.
class Created(models.Model):
id = models.AutoField(primary_key=True)
created = models.DateField(default=timezone.now)
class Meta:
abstract = True
class UniqueName(Created):
name = models.CharField(unique=True, max_length=200)
class Meta:
abstract = True
class Categories(UniqueName):
...
class Answers(Created):
name = models.CharField(max_length=200)
correct = models.BooleanField(default=False)
class Questions(UniqueName):
category = models.ForeignKey(Categories, on_delete=models.CASCADE)
answers = models.ManyToManyField(Answers, related_name="question")
@property
def correct_answer(self):
return self.answers.filter(correct=True).first()
Вывод json выглядит следующим образом:
{
"category":"Harry Potter2",
"questions":[
{
"name":"What is Harrys Name",
"answers":[
{
"name":"Potter",
"correct": true
},
{
"name":"blabla"
}
]
},
{
"name":"What is Hermion Name",
"answers":[
{
"name":"Grenger",
"correct": true
},
{
"name":"blabla"
}
]
}
]
}
В настоящее время я обрабатываю это в своем представлении (что не является элегантным).
category, _ = models.Categories.objects.get_or_create(name=data.category)
for q_obj in data.questions:
question, _ = models.Questions.objects.get_or_create(
name=q_obj.name, category=category
)
for a_obj in q_obj.answers:
if not question.answers.filter(name=a_obj.name).first():
answer = models.Answers.objects.create(
name=a_obj.name, correct=a_obj.correct
)
question.answers.add(answer)
Я хотел бы перенести эту логику в сериализатор, но не представляю, как их объединить. Буду благодарен за любые подсказки. Спасибо!
Вы можете перенести логику из представления в сериализатор, создав пользовательский метод create() для вашего сериализатора. Этот метод будет вызываться при вызове serializer.save(), и он позволит вам настроить способ сохранения данных из сериализатора в базу данных.
Вот пример того, как это можно сделать:
class QuestionsSerializer(serializers.ModelSerializer):
# Define the answers field as a nested serializer
answers = AnswersSerializer(many=True)
class Meta:
model = Questions
fields = ['name', 'answers']
def create(self, validated_data):
# Extract the answers data from the validated data
answers_data = validated_data.pop('answers')
# Create the question instance using the remaining validated data
question = Questions.objects.create(**validated_data)
# Iterate over the answers data and create answer instances
for answer_data in answers_data:
# Create the answer instance
answer = Answers.objects.create(**answer_data)
# Add the answer to the question
question.answers.add(answer)
# Return the created question instance
return question
В приведенном выше коде метод create() сначала извлекает данные ответов из проверенных данных, затем создает экземпляр Questions, используя оставшиеся проверенные данные. Затем он выполняет итерации над данными ответов, создавая экземпляры Answers и добавляя их к экземпляру Questions. Наконец, он возвращает созданный экземпляр Questions.
Затем вы можете использовать этот сериализатор в своем представлении для создания экземпляров вопросов и ответов из входных данных. Вот пример того, как это можно сделать:
class QuestionsView(APIView):
def post(self, request):
# Create a serializer instance using the input data
serializer = QuestionsSerializer(data=request.data)
# Validate the data and save the serializer
serializer.is_valid(raise_exception=True)
question = serializer.save()
# Return a response with the created question
return Response(QuestionsSerializer(question).data)
В приведенном выше коде, QuestionsSerializer используется для проверки и сохранения входных данных, а созданный экземпляр Questions возвращается в ответе.
Затем вы можете использовать аналогичный подход для модели Categories, создав пользовательский метод create() в CategoriesSerializer для обработки создания экземпляров Categories и Questions из входных данных.