Короткий ответ
bulk_create()/bulk_update() формируют один (или несколько батчами) SQL-запрос на вставку/обновление множества объектов сразу вместо отдельного INSERT/UPDATE на каждый объект в цикле, что резко снижает число round-trip'ов к БД; ограничения — они не вызывают save()/сигналы Django для каждого объекта.
Как это работает подробнее
Обычный цикл for obj in objects: obj.save() выполняет отдельный запрос на каждый объект; bulk_create собирает один многострочный INSERT (батчами, управляется batch_size), bulk_update формирует CASE WHEN-конструкцию или несколько UPDATE одним проходом.
Пример кода
example.py
# Плохо: N отдельных INSERT
for row in import_rows:
Product.objects.create(sku=row["sku"], price=row["price"])
# Хорошо: один (или несколько батчами) INSERT
products = [Product(sku=row["sku"], price=row["price"]) for row in import_rows]
Product.objects.bulk_create(products, batch_size=500)
# Сигналы post_save НЕ будут вызваны для каждого объекта — это нужно учитывать явноЧто использовать на практике
- Практика. bulk_* операции применяют при массовом импорте/синхронизации данных; pre_save/post_save сигналы не вызываются, поэтому побочная логика, завязанная на сигналы, должна быть продублирована явно при необходимости.
Подводные камни
- Ошибка. Ожидают, что bulk_create выполнит кастомную логику переопределённого save() — это не так; не указывают batch_size для очень большого количества объектов, что может создать один гигантский SQL-запрос.