Обновление нескольких вложенных объектов в DRF

У меня есть три связанные модели с отношениями полей "многие ко многим".

У меня нет идеи, как я могу обновить все экземпляры одновременно.

Я хотел бы создать три отдельных сериализатора, которые могли бы обновлять три экземпляра.

class PlannedChargePriceSerializer(serializers.ModelSerializer):
    class Meta:
        model = ChargePrice
        fields = ['id', 'start', 'end', 'price']

class PlannedChargeSerializer(serializers.ModelSerializer):
    prices = PlannedChargePriceSerializer(many=True)

    class Meta:
        model = Charge
        fields = ['id', 'type', 'qtd', 'status', 'prices']

class PlannedSerializer(serializers.ModelSerializer):
    charges = PlannedChargeSerializer(many=True)

    class Meta:
        model = Planned
        fields = '__all__'
        read_only_fields = ['id', 'date', 'charges']

    def create(self, validated_data):
        charges_data = validated_data.pop('charges')
        planned = Planned.objects.create(**validated_data)

        for charge_data in charges_data:
            charge_prices_data = charge_data.pop('prices')
            charge = Charge.objects.create(planned=planned, **charge_data)

            for charge_price_data in charge_prices_data:
                ChargePrice.objects.create(charge=charge, **charge_price_data)

        return planned

    def update(self, instance, validated_data):
        # No idea how update multiple nested objects
        return instance

В документации Django REST Framework говорится:

По умолчанию вложенные сериализаторы доступны только для чтения. Если вы хотите поддерживать операции записи в поле вложенного сериализатора, вам нужно будет создать методы create() и/или update(), чтобы явно указать, как должны сохраняться дочерние отношения.

Короче говоря, готового решения не существует, вам придется писать сериализатор самостоятельно.

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

   def update(self, instance, validated_data):
    instance = super().update(instance, validated_data)
    updated_charges = validated_data.pop('charges', [])

    if updated_charges:
        existing_charges = {charge.id: charge for charge in instance.charges.all()}

        for charge_info in updated_charges:
            charge_id = charge_info.get('id')
            charge_prices_info = charge_info.pop('prices', [])

            if charge_id in existing_charges:
                current_charge = existing_charges[charge_id]
                for field, value in charge_info.items():
                    setattr(current_charge, field, value)
                current_charge.save()

                if charge_prices_info:
                    existing_prices = {price.id: price for price in current_charge.prices.all()}

                    for price_info in charge_prices_info:
                        price_id = price_info.get('id')

                        if price_id in existing_prices:
                            current_price = existing_prices[price_id]
                            for field, value in price_info.items():
                                setattr(current_price, field, value)
                            current_price.save()
                        else:
                            ChargePrice.objects.create(charge=current_charge, **price_info)
            else:
                new_charge = Charge.objects.create(planned=instance, **charge_info)

                if charge_prices_info:
                    for price_info in charge_prices_info:
                        ChargePrice.objects.create(charge=new_charge, **price_info)

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