Вопрос или проблема
У меня есть три связанные модели с отношением “многие ко многим”.
У меня нет идеи, как обновить все экземпляры сразу.
Я хотел бы создать три отдельных сериализатора, которые могли бы обновить три экземпляра.
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):
# Никакой идеи, как обновить несколько вложенных объектов
return instance
Ответ или решение
Для обновления нескольких связанных объектов в Django REST Framework (DRF) с использованием вложенных сериализаторов, нам необходимо не только реализовать логику обновления для базового объекта, но и корректно обработать изменения связанных объектов (в вашем случае — это объекты Charge
и ChargePrice
).
Разберем обновление, шаг за шагом, используя ваш код в качестве основы.
Обновление вложенных объектов
- Получение вложенных данных: Извлекаем данные из
validated_data
. - Обновление существующих объектов: Для каждой связи проверяем, существует ли объект и обновляем его, иначе создаем новый.
- Обработка списка цен: Обновляем или создаем связанные объекты
ChargePrice
.
Вот как будет выглядеть метод update
:
def update(self, instance, validated_data):
charges_data = validated_data.pop('charges', [])
# Обновляем основные поля объекта Planned
instance.some_field = validated_data.get('some_field', instance.some_field) # Пример обновления поля
instance.save()
# Сохраняем обновленные или создаем новые Charge
existing_charges_ids = [charge.id for charge in instance.charges.all()]
new_charge_ids = []
for charge_data in charges_data:
charge_id = charge_data.get('id', None)
prices_data = charge_data.pop('prices', [])
if charge_id in existing_charges_ids:
# Если Charge уже существует, обновляем его
charge = Charge.objects.get(id=charge_id, planned=instance)
charge.type = charge_data.get('type', charge.type)
charge.qtd = charge_data.get('qtd', charge.qtd)
charge.status = charge_data.get('status', charge.status)
charge.save()
else:
# Если Charge не существует, создаем его
charge = Charge.objects.create(planned=instance, **charge_data)
new_charge_ids.append(charge.id)
# Сохраняем или обновляем ChargePrice
existing_prices_ids = [price.id for price in charge.prices.all()]
for price_data in prices_data:
price_id = price_data.get('id', None)
if price_id in existing_prices_ids:
# Обновляем существующую цену
price = ChargePrice.objects.get(id=price_id, charge=charge)
price.start = price_data.get('start', price.start)
price.end = price_data.get('end', price.end)
price.price = price_data.get('price', price.price)
price.save()
else:
# Создаем новую цену
ChargePrice.objects.create(charge=charge, **price_data)
# Удаляем Charge, если они не включены в запрос
for charge in instance.charges.exclude(id__in=new_charge_ids):
charge.delete()
return instance
Пояснения к коду:
- Обновление основного объекта: Извлекаем данные
validated_data
и обновляем необходимые поля основного объектаPlanned
. - Работа с объектами Charge: Проверяем, существуют ли переданные объекты
Charge
. Если они существуют, обновляем их. Если нет — создаем новые. - Работа с объектами ChargePrice: Аналогично обновляем существующие цены и создаем новые по мере необходимости.
- Удаление старых объектов: Если какие-то объекты
Charge
больше не указаны в данных запроса, мы можем удалить их.
Этот подход сохраняет целостность данных и управляет обновлением вложенных объектов в соответствии с вашими требованиями в рамках DRF. Надеюсь, это поможет вам эффективно обновлять ваши вложенные объекты!