Home > Enterprise >  bulk create in django with foreign key
bulk create in django with foreign key

Time:07-20

Models:

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)

I have an api to create a book, and along with the book data we would also get a list of author ids.

Now for each book we need to create one/more records (depending on the author ids provided) in the AuthorBookAssn table.

What is the best way to do this and can the create be done in bulk. Currently the approach is to get the author objects for each of the ids in the list and then call

AuthorBookAssn.objects.create(book=book_instance,author=author_instance)

CodePudding user response:

You've created a many-to-many relationship so your current method is the only possible way based on your current structure. If you were to use Django's in-built m2m field then you would essentially do the same except you would do something like author.books.add(book), but again, you would have to do this separately to your book/author creation. An alternative would be to use a many-to-one relation (i.e. ForeignKey field) which would allow you to connect the two when an object is created. Many-to-One might not be how you want to structure things if books can have multiple authors and vice-versa.

CodePudding user response:

(supplementary to OsVoid's answer)

There might be some degree of optimization by working with the object ids (primary key values) rather than fetching the entire objects. Premature optimization is a bad idea, and you'd have to benchmark this idea to see if any improvement is measurable (assuming you have any need to optimize at all).

Given book_pk and author_pk you can use the "magic" _id suffix:

AuthorBookAssn.objects.create(book_id=book_pk,author_id=author_pk)

And instead of fetching whole objects, you might fetch just their pk values using a .values_list('pk') in a queryset. (with flat=True if only the one value is being requested). Since this is just a number, it also might be possible to attach it to some other objects that you really do need to obtain, using annotation.

Also, you can cause your own model to be used for the association in a Django ManyToMany relation, using "through". This is valuable if you want to store extra information about the association, such as when it was created, who by, for what purpose, etc.

  • Related