Главные риски — изменение входного словаря через pop() и частично созданная книга при ошибке одной обложки. Создание книги и связей нужно объединить transaction.atomic(), а входные данные не мутировать.
Создание записи книги и её обложек через API‑запрос
Главные риски — изменение входного словаря через pop() и частично созданная книга при ошибке одной обложки. Создание книги и связей нужно объединить transaction.atomic(), а входные данные не мутировать.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
При получении POST‑запроса, инициирующего добавление новой книги, вызывается функция create_book. Она формирует объект Book, а затем создаёт связанные записи BookCover. Требуется провести ревью кода: оценить корректность и надёжность процесса создания сущностей, выявить потенциальные проблемы с транзакционной согласованностью и возможные места для оптимизации.
def create_book(validate_data: dict):
covers: list[dict] = validate_data.pop('covers')
book = Book.objects.create(**validate_data)
for cover in covers:
BookCover.objects.create(**cover, book_id=book.id)
Ответ
Главные риски — изменение входного словаря через pop() и частично созданная книга при ошибке одной обложки. Создание книги и связей нужно объединить transaction.atomic(), а входные данные не мутировать.
Вариант после валидации полей:
from django.db import transaction
def create_book(validated_data):
data = dict(validated_data)
covers = data.pop('covers', [])
with transaction.atomic():
book = Book.objects.create(**data)
BookCover.objects.bulk_create([
BookCover(book=book, **cover) for cover in covers
])
return book
Поля book/book_id нельзя принимать внутри cover от клиента. bulk_create уменьшает число запросов, но обходит обычные save() и сигналы; если они нужны, оставьте цикл в транзакции. Транзакция БД не откатывает загрузку файлов во внешнее хранилище.
Источник: docs.djangoproject.com.