Как метод save() в Django определяет, выполнять INSERT или UPDATE?

«Как метод save() в Django определяет, выполнять INSERT или UPDATE?» — вопрос из категории Django, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Django ORM определяет, какую SQL-операцию выполнять (INSERT или UPDATE), на основе состояния первичного ключа (primary_key) экземпляра модели.

Основная логика:

  1. INSERT (создание): Выполняется, если у объекта отсутствует значение первичного ключа (атрибут pk или id равен None). Это означает, что объект еще не сохранен в базе данных.

  2. UPDATE (обновление): Выполняется, если у объекта установлен первичный ключ. Django предполагает, что раз pk существует, то соответствующая запись уже есть в таблице и ее нужно обновить.

Пример:

from myapp.models import Product

# 1. Создание нового объекта -> INSERT
# pk здесь равен None
new_product = Product(name="Ноутбук", price=999.99)
new_product.save() # Выполняется SQL INSERT
# После сохранения new_product.pk получит значение от БД

# 2. Обновление существующего объекта -> UPDATE
# Получаем объект из БД, его pk уже определен
product_to_update = Product.objects.get(pk=new_product.pk)
product_to_update.price = 899.99 # Изменяем поле
product_to_update.save() # Выполняется SQL UPDATE

Дополнительные возможности:

  • force_insert=True: Принудительно выполнит INSERT, даже если pk задан. Если запись с таким pk уже существует, возникнет ошибка IntegrityError.
  • force_update=True: Принудительно выполнит UPDATE. Если запись с таким pk не найдена, будет выброшено исключение.
  • update_fields: Для повышения производительности можно указать, какие именно поля обновлять: obj.save(update_fields=['price', 'name']). В этом случае будет сгенерирован более легковесный UPDATE-запрос.