Какие существуют способы обновления объекта модели в Django ORM?

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

Ответ

В Django ORM для обновления данных объекта модели существуют два основных подхода, различающихся производительностью и поведением.

1. Метод instance.save()

Этот способ предполагает сначала загрузку объекта из базы данных в память, изменение его полей, а затем сохранение обратно.

Как это работает:

  1. Выполняется SQL-запрос SELECT для получения объекта.
  2. Атрибуты объекта изменяются в Python.
  3. Выполняется SQL-запрос UPDATE для сохранения изменений.

Пример:

from django.contrib.auth.models import User

# Требуется 2 запроса к БД (SELECT, затем UPDATE)
user = User.objects.get(id=1)
user.username = 'new_username'
user.email = 'new@example.com'
user.save()

Преимущества:

  • Вызывает сигналы pre_save и post_save.
  • Запускает пользовательскую логику, переопределенную в методе save().

2. Метод QuerySet.update()

Этот способ более эффективен, так как выполняет один прямой SQL-запрос UPDATE к базе данных без необходимости загружать объект в память.

Пример:

from django.contrib.auth.models import User

# Выполняется 1 запрос к БД (UPDATE)
updated_rows_count = User.objects.filter(id=1).update(username='new_username', email='new@example.com')

Важные ограничения:

  • Не вызывает сигналы pre_save и post_save.
  • Не вызывает переопределенный метод save() модели.
  • Не обновляет поле auto_now у DateTimeField.

Ключевые отличия и рекомендации

Критерий instance.save() QuerySet.update()
Производительность Ниже (минимум 2 запроса) Выше (1 запрос)
Вызов сигналов Да Нет
Вызов метода save() Да Нет
Массовое обновление Неэффективно Эффективно

Вывод:

  • Используйте QuerySet.update() для простых и массовых обновлений, где не требуется дополнительная логика (сигналы, кастомный save).
  • Используйте instance.save() когда необходимо, чтобы сработали сигналы или другая бизнес-логика, связанная с сохранением объекта.
  • Для смены пароля пользователя всегда используйте user.set_password('new_pass') и затем user.save(), чтобы обеспечить корректное хеширование.