Ответ
В Django ORM для обновления данных объекта модели существуют два основных подхода, различающихся производительностью и поведением.
1. Метод instance.save()
Этот способ предполагает сначала загрузку объекта из базы данных в память, изменение его полей, а затем сохранение обратно.
Как это работает:
- Выполняется SQL-запрос
SELECTдля получения объекта. - Атрибуты объекта изменяются в Python.
- Выполняется 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(), чтобы обеспечить корректное хеширование.