Как в Django REST Framework создать или обновить экземпляр модели из валидированного сериализатора?

Ответ

В Django REST Framework для создания или обновления экземпляра модели из данных сериализатора используется метод .save().

Этот метод можно вызывать только после успешной валидации данных с помощью serializer.is_valid().

Как работает .save():

В зависимости от того, как был инициализирован сериализатор, .save() вызывает один из двух методов:

  • .create(validated_data) — если сериализатор был создан только с data (создание нового объекта).
  • .update(instance, validated_data) — если сериализатор был создан с instance и data (обновление существующего объекта).

Пример создания (Create):

# request.data = {'name': 'New Product', 'price': 150.0}
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
    # Вызывает ProductSerializer.create()
    new_product = serializer.save()
    # new_product - это созданный экземпляр модели Product

Пример обновления (Update):

product_instance = Product.objects.get(pk=1)
# request.data = {'price': 200.0}
serializer = ProductSerializer(instance=product_instance, data=request.data, partial=True)
if serializer.is_valid():
    # Вызывает ProductSerializer.update()
    updated_product = serializer.save()
    # updated_product - это обновленный экземпляр

Метод .save() также может принимать дополнительные аргументы, которые будут переданы в .create() или .update(). Это полезно для установки полей, которые не приходят от клиента, например, owner:

serializer.save(owner=request.user)

Ответ 18+ 🔞

А, слушай, ну вот смотри, тут про Django REST Framework речь. Есть у них такой магический метод .save(). Ну, не то чтобы магический, но без него нихуя не работает, когда нужно записать данные из сериализатора в базу — либо создать новую запись, либо обновить старую.

Но, внимание, ёпта, важный момент! Эту штуку можно вызывать только после того, как данные прошли валидацию. То есть ты сначала делаешь serializer.is_valid(), и если он не сказал, что всё хуёво, только тогда уже можно .save() пинать. Иначе — пиздец, исключение полети́т, и всё накроется медным тазом.

Как эта хрень работает внутри:

Всё зависит от того, как ты сериализатор инициализировал. Метод .save() сам догадается, что ему делать:

  • .create(validated_data) — вызовется, если ты передал в сериализатор только data. Это значит «создай мне новый объект, блядь».
  • .update(instance, validated_data) — вызовется, если ты передал и instance (существующий объект), и data. Это уже «обнови эту старую хуйню».

Пример, когда мы создаём что-то новое (Create):

# Допустим, пришло request.data = {'name': 'Новый Продукт', 'price': 150.0}
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():  # Проверили, что данные не бредовые
    # Тут вызывается внутренний метод ProductSerializer.create()
    new_product = serializer.save()
    # И вот new_product — это уже свежеиспечённый экземпляр модели Product, лежит в базе!

А вот пример, когда мы старую запись обновляем (Update):

# Нашли в базе старый продукт
product_instance = Product.objects.get(pk=1)
# Пришло request.data = {'price': 200.0} (только цену поменять хотим)
serializer = ProductSerializer(instance=product_instance, data=request.data, partial=True) # partial=True — чтобы можно было не все поля слать
if serializer.is_valid():
    # А тут уже вызовется ProductSerializer.update()
    updated_product = serializer.save()
    # И updated_product — это тот же самый объект, но уже с новой ценой, охуенно!

И ещё фишка, блядь! В .save() можно передать дополнительные аргументы, которые просочатся прямо в .create() или .update(). Зачем? Ну, например, чтобы проставить поле owner, которое от клиента не приходит, а берётся из запроса:

serializer.save(owner=request.user)  # Типа «вот хозяин объекта, запоминай»

Вот и вся магия, не так страшен чёрт, как его малюют. Главное — валидируй перед сохранением, а то будет тебе волнение ебать и терпения ноль ебать.