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 из входных данных.

Вернуться на верх