Сериализатор с возможностью записи

У меня есть следующие наборы представлений и сериализаторы, настроенные для создания одного действия для публикации расписания с его шагами, но я получаю следующую ошибку.



class StepCreateSerializer(serializers.Serializer):
    start_time = serializers.TimeField()
    time = serializers.IntegerField()

    def update(self, instance, validated_data):
        pass

    def create(self, validated_data):
        print(validated_data)
        return validated_data


class ScheduleCreateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=100)
    identifier = serializers.CharField(max_length=10)
    steps = StepCreateSerializer(many=True)

    def update(self, instance, validated_data):
        pass

    def create(self, validated_data):
        steps_data = validated_data.get('steps', [])
        schedule = Schedule.objects.create(**validated_data)
        for step_data in steps_data:
            Step.objects.create(schedule=schedule, **steps_data)
        return schedule


class ScheduleViewSet(BaseViewSet):
    queryset = Schedule.objects.all()
    serializer_class = ScheduleSerializer

    def create(self, request, *args, **kwargs):
        ser = ScheduleCreateSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return Response()

Я вызываю его со следующей полезной нагрузкой json с методом POST:

{
    "name": "Schedule123",
    "identifier": "S123",
    "steps": [
        {
            "start_time": "07:21:00",
            "time": 5,
            "valve_actions": [
                {
                    "start_state": true,
                    "end_state": false,
                    "valve": 2
                },
                {
                    "start_state": true,
                    "end_state": false,
                    "valve": 1
                }
            ]
        }
    ]
}

При вызове с полезной нагрузкой

возникает следующая ошибка
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use steps.set() instead.

Модели следующие

class Schedule(models.Model):
    identifier = models.CharField(max_length=10)
    name = models.CharField(max_length=100)

class Step(models.Model):
    start_time = models.TimeField()
    time = models.IntegerField()
    schedule = models.ForeignKey("manager.Schedule", on_delete=models.CASCADE, related_name="steps",
                                 null=True)

Как создать шаги для расписания с помощью одного действия post? Я пытаюсь написать одно действие для отправки полезной нагрузки, и оно должно создавать шаги для расписания

Если вы поддерживаете вложенные представления с возможностью записи, вам нужно написать .create() метод, который обрабатывает сохранение нескольких объектов.

В вашем примере вы хотите определить ScheduleCreateSerializer таким образом:

class ScheduleCreateSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=100)
    identifier = serializers.CharField(max_length=10)
    steps = StepCreateSerializer(many=True)

    def create(self, validated_data):
        # use .pop() to remove steps from valiated_data
        steps_data = validated_data.pop('steps', [])

        schedule = Schedule.objects.create(**validated_data)
        
        # your should use step_data not steps_data in the for loop
        for step_data in steps_data:
            Step.objects.create(schedule=schedule, **step_data)

        # or a better optimization is to use bulk_create to save trips to DB
        Step.objects.bulk_create([
            Step(**data)
            for data in steps_data
        ])
        
        return schedule

Аналогично, если вы хотите использовать тот же сериализатор для поддержки обновлений, вам нужно будет определить метод update() в сериализаторе.

Ref: https://www.django-rest-framework.org/api-guide/serializers/#writing-create-methods-for-nested-representations

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