← Назад к вопросам
Расскажи как делать транзакции в Django ORM
1.8 Middle🔥 131 комментариев
#Django#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Транзакции в Django ORM
Транзакция — это последовательность операций БД, которые либо все выполняются успешно (commit), либо все откатываются (rollback). Django предоставляет несколько способов управления транзакциями.
1. Контекстный менеджер @transaction.atomic()
Наиболее распространённый способ — использовать декоратор или контекстный менеджер:
from django.db import transaction
# Как декоратор
@transaction.atomic
def create_order_with_items(user, items):
order = Order.objects.create(user=user, total=0)
total = 0
for item_id, quantity in items:
product = Product.objects.get(id=item_id)
OrderItem.objects.create(
order=order,
product=product,
quantity=quantity,
price=product.price
)
total += product.price * quantity
order.total = total
order.save()
return order
# Как контекстный менеджер
def transfer_funds(from_account, to_account, amount):
with transaction.atomic():
from_account.balance -= amount
from_account.save()
to_account.balance += amount
to_account.save()
2. Уровни изоляции
Django поддерживает разные уровни изоляции:
from django.db import transaction
# READ_COMMITTED (по умолчанию в PostgreSQL)
with transaction.atomic():
user = User.objects.select_for_update().get(id=user_id)
user.balance -= 100
user.save()
# SERIALIZABLE (максимальная безопасность)
with transaction.atomic(durable=True):
# операции
pass
3. SELECT FOR UPDATE
Для защиты от race conditions используй select_for_update() — это блокирует строку для обновления:
def decrement_inventory(product_id, quantity):
with transaction.atomic():
product = Product.objects.select_for_update().get(id=product_id)
if product.stock >= quantity:
product.stock -= quantity
product.save()
return True
return False
4. Savepoints
Сохранить частичный откат внутри транзакции:
with transaction.atomic():
Order.objects.create(user=user, total=100)
sid = transaction.savepoint() # Сохраняем состояние
try:
payment = process_payment(user, 100)
except PaymentError:
transaction.savepoint_rollback(sid) # Откатываемся только платёж
payment = None
if payment:
transaction.savepoint_commit(sid)
5. Управление на уровне БД
from django.db import connection, transaction
# Отключить автокоммит
with transaction.atomic(using="default"):
# вся логика будет в одной транзакции
pass
# Явный commit/rollback (редко используется)
cursor = connection.cursor()
try:
cursor.execute("UPDATE accounts SET balance = balance - %s WHERE id = %s", [100, 1])
connection.commit() # Явный коммит
except Exception:
connection.rollback()
raise
6. Ошибки и лучшие практики
# ❌ Плохо — долгие операции в транзакции
with transaction.atomic():
order = Order.objects.create(user=user)
time.sleep(5) # Блокирует БД
send_email_async(user) # Отправка должна быть вне транзакции
# ✅ Хорошо — короткие транзакции, асинхронные операции вне
with transaction.atomic():
order = Order.objects.create(user=user)
celery_task_send_email.delay(user.id)
# ❌ Плохо — вложенные atomic без savepoints
with transaction.atomic():
obj1.save()
with transaction.atomic(): # Новая транзакция создаёт savepoint
obj2.save()
# ✅ Хорошо — обработка IntegrityError
from django.db import IntegrityError
with transaction.atomic():
try:
user = User.objects.create(email=email, username=username)
except IntegrityError:
# Email уже существует
user = User.objects.get(email=email)
7. Проверка статуса
# Проверить, находимся ли в транзакции
if transaction.get_connection().in_atomic_block:
print("Мы в транзакции")
# Отключить транзакции для конкретного запроса
User.objects.using(read_only).filter(id=1) # В отдельном соединении
Ключевые принципы
- Держи транзакции короткими — минимизируй время блокировки
- Используй atomic() для атомарности — либо всё, либо ничего
- Защищай от race conditions — select_for_update() для конкурентного доступа
- Обрабатывай ошибки — IntegrityError, OperationalError
- Асинхронные операции вне транзакции — используй Celery для email/API
Транзакции в Django — это основа надёжного взаимодействия с БД, особенно в многопользовательских системах с высокой конкуренцией.