Обновление нескольких вложенных объектов в 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