Функция atomic

Функция atomic из модуля django.db используется для создания атомарных блоков операций с базой данных. Она применяется как декоратор к функциям или как контекстный менеджер в блоке with. Все операции внутри такого блока выполняются в рамках одной транзакции - если возникает исключение, все изменения откатываются, а если блок завершается успешно, все изменения фиксируются. Функция принимает необязательный параметр using, который указывает, к какой базе данных применять транзакцию, и параметр savepoint, который управляет созданием точек сохранения при вложенных вызовах atomic.

Синтаксис

pythonfrom django.db import atomic

# Как контекстный менеджер
with atomic(using='default', savepoint=True):
  # операции с базой данных

# Как декоратор
@atomic(using='default', savepoint=True)
def view_function(request):
  # операции с базой данных

Пример

Давайте создадим атомарный блок для перевода денег между счетами, где оба изменения должны быть выполнены вместе:

pythonfrom django.db import atomic, transaction
from myapp.models import Account

def transfer_money(from_id, to_id, amount):
  try:
    with atomic():
      from_account = Account.objects.select_for_update().get(id=from_id)
      to_account = Account.objects.select_for_update().get(id=to_id)

      if from_account.balance < amount:
        raise ValueError("Insufficient funds")

      from_account.balance -= amount
      to_account.balance += amount

      from_account.save()
      to_account.save()

    print("Transfer completed successfully")
    return True

  except Exception as e:
    print(f"Transfer failed: {e}")
    return False

Результат выполнения кода при успешном переводе:

python"Transfer completed successfully"

Пример

Используем atomic как декоратор для представления, которое создает заказ и обновляет количество товара:

pythonfrom django.db import atomic
from myapp.models import Order, Product

@atomic
def create_order(product_id, quantity, user):
  product = Product.objects.select_for_update().get(id=product_id)

  if product.stock < quantity:
    raise ValueError("Not enough stock")

  order = Order.objects.create(
    user=user,
    product=product,
    quantity=quantity,
    total=product.price * quantity
  )

  product.stock -= quantity
  product.save()

  return order

Результат выполнения кода при успешном создании заказа:

python"Order created: 1024"

Пример

Рассмотрим вложенные транзакции с использованием параметра savepoint для создания точек сохранения:

pythonfrom django.db import atomic
from myapp.models import Article

def create_article_with_tags(title, content, tags):
  try:
    with atomic():
      article = Article.objects.create(
        title=title,
        content=content,
        status='draft'
      )

      # Внутренний блок с точкой сохранения
      with atomic(savepoint=True):
        for tag in tags:
          article.tags.add(tag)
        # Если здесь произойдет ошибка, статья сохранится,
        # а теги не добавятся

      print(f"Article {article.id} created with {len(tags)} tags")
      return article

  except Exception as e:
    print(f"Failed to create article: {e}")
    return None

Результат выполнения кода при успешном создании:

python"Article 5 created with 3 tags"

Смотрите также

  • функция on_commit,
    которая выполняет действия после успешной фиксации транзакции
  • метод select_for_update,
    который блокирует строки для предотвращения конкурентных изменений
  • метод get_or_create,
    который получает или создает объект в рамках транзакции
  • метод update_or_create,
    который обновляет или создает объект в рамках транзакции