Как реализовать атомарную транзакцию для API эндпоинта в Django?

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

Ответ

Для обеспечения атомарности операций с базой данных в рамках одного API-запроса в Django используется декоратор transaction.atomic.

Он гарантирует, что все изменения в БД либо будут успешно применены (commit), либо полностью отменены (rollback) в случае возникновения исключения. Это критически важно для сохранения целостности данных.

Для Function-Based Views (FBV)

Декоратор применяется непосредственно к функции представления.

from django.db import transaction
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['POST'])
@transaction.atomic
def create_order(request):
    try:
        # Пример: создание заказа и списание товара со склада
        order = create_order_in_db(request.data)
        update_stock_count(order.product, order.quantity)

        # Все операции с БД здесь атомарны
        return Response({'status': 'success'}, status=status.HTTP_201_CREATED)

    except Exception as e:
        # При любом исключении транзакция автоматически откатится
        return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)

Для Class-Based Views (CBV)

Для применения транзакций к методам в классовых представлениях (например, post, put) используется method_decorator:

from django.db import transaction
from django.utils.decorators import method_decorator
from rest_framework.views import APIView
from rest_framework.response import Response

class OrderAPIView(APIView):
    @method_decorator(transaction.atomic)
    def post(self, request, *args, **kwargs):
        # Логика, требующая транзакционности, находится здесь
        # ...
        return Response({'status': 'success'})

Также можно применить декоратор ко всему классу через dispatch, чтобы все HTTP-методы выполнялись в транзакции: @method_decorator(transaction.atomic, name='dispatch').