Массовое создание в django с внешним ключом
Модели:
class Author(Base):
name = models.CharField(max_length=100, unique=True)
class Book(Base):
name = models.CharField(max_length=100, unique=True)
class AuthorBookAssn(Base):
author = models.ForeignKey(Author, on_delete=models.PROTECT)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
У меня есть api для создания книги, и вместе с данными о книге мы также получаем список идентификаторов авторов.
Теперь для каждой книги нам нужно создать одну или несколько записей (в зависимости от предоставленных идентификаторов авторов) в таблице AuthorBookAssn.
Каков наилучший способ сделать это и можно ли создавать объекты массово. В настоящее время подход заключается в получении объектов автора для каждого из идентификаторов в списке и последующем вызове
AuthorBookAssn.objects.create(book=book_instance,author=author_instance)
Вы создали отношение "многие ко многим", поэтому ваш текущий метод является единственным возможным способом, основанным на вашей текущей структуре. Если бы вы использовали встроенное в Django поле m2m, вы бы сделали то же самое, за исключением того, что вы бы сделали что-то вроде author.books.add(book)
, но опять же, вам пришлось бы делать это отдельно от создания книги/автора. Альтернативой может быть использование отношения "многие-к-одному" (т.е. поля ForeignKey), которое позволит вам соединить эти две связи при создании объекта. Отношение "многие к одному" может быть не тем, как вы хотите структурировать вещи, если у книг может быть несколько авторов и наоборот.
(дополнение к ответу OsVoid)
Возможна некоторая степень оптимизации за счет работы с идентификаторами объектов (значениями первичных ключей) вместо получения целых объектов. Преждевременная оптимизация - плохая идея, и вам придется провести сравнительный анализ этой идеи, чтобы увидеть, можно ли измерить какое-либо улучшение (если предположить, что у вас вообще есть необходимость в оптимизации).
Учитывая book_pk
и author_pk
можно использовать "волшебный" суффикс _id
:
AuthorBookAssn.objects.create(book_id=book_pk,author_id=author_pk)
Вместо получения целых объектов, вы можете получить только их значения pk, используя .values_list('pk')
в наборе запросов (с flat=True
, если запрашивается только одно значение). Поскольку это просто число, его также можно прикрепить к некоторым другим объектам, которые вам действительно нужно получить, используя аннотацию.
Кроме того, вы можете заставить свою собственную модель использоваться для ассоциации в отношении Django ManyToMany, используя "through". Это ценно, если вы хотите хранить дополнительную информацию об ассоциации, например, когда она была создана, кем, с какой целью и т.д.