Suppose you want to do something like this:
new_entries = Entry.objects.bulk_create(
entries, batch_size=300
)
and you expect your output, new_entries, to contain the newly inserted primary keys, but they don’t.
This article tells you clearly under what circumstances this doesn’t happen.
You’re using a database that doesn’t support AutoField for primary keys.
You have a setting for conflict and it isn’t
update on conflict
Using the Right Database and AutoField for PK
In the Django documentation, it even states this clearly
If the model’s primary key is an
AutoField
, the primary key attribute can only be retrieved on certain databases (currently PostgreSQL, MariaDB, and SQLite 3.35+). On other databases, it will not be set.— QuerySet API reference | Django documentation | dev branch
By AutoField, that also includes BigAutoField and other subclasses of AutoField.
In other words, for certain databases, if you’re using AutoField or its subclasses as primary key, then, so far so good, yes, bulk_create will return you the created ids.
Yes, I said, so far so good. Because, and this is the annoying part, that’s only half the story.
You ALSO NEED TO AVOID ignore on conflict.
Avoid Ignore on Conflict
I did this and I did NOT get back the created ids.
new_entries = Entry.objects.bulk_create(
entries, batch_size=300,
ignore_conflicts=True # new_entries NO longer have ids
)
This was definitely not documented at the time of writing.
A severe gotcha that ate hours of my time, debugging.
This line in GitHub proved this point.
Long story short, you need to do ALL 3 of the following to get back your created ids when using bulk_create:
Use the right database
Use AutoField or its subclasses as primary key
Avoid
ignore_conflicts=True
If you’ll excuse me, I’m going to file a pull request to improve the documentation.
Update: I have sent a pull request to improve the docs. Let’s see what happens next.