Opened 17 months ago
Closed 16 months ago
#34698 closed New feature (fixed)
Allow returning IDs in QuerySet.bulk_create() when updating conflicts.
Reported by: | Thomas C | Owned by: | Thomas C |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.2 |
Severity: | Normal | Keywords: | |
Cc: | Chih Sean Hsu | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Currently, when using bulk_create
with a conflict handling flag turned on (e.g. ignore_conflicts
or update_conflicts
), the primary keys are not set in the returned queryset, as documented in bulk_create
.
While I understand using ignore_conflicts
can lead to PostgreSQL not returning the IDs when a row is ignored (see this SO thread), I don't understand why we don't return the IDs in the case of update_conflicts
.
For instance:
MyModel.objects.bulk_create([MyModel(...)], update_conflicts=True, update_fields=[...], unique_fields=[...])
generates a query without a RETURNING my_model.id
part:
INSERT INTO "my_model" (...) VALUES (...) ON CONFLICT(...) DO UPDATE ...
If I append the RETURNING my_model.id
clause, the query is indeed valid and the ID is returned (checked with PostgreSQL).
I investigated a bit and this in Django source is where the returning_fields
gets removed.
I believe we could discriminate the cases differently so as to keep those returning_fields
in the case of update_conflicts
.
This would be highly helpful when using bulk_create
as a bulk upsert feature.
Change History (6)
comment:1 by , 17 months ago
Cc: | added |
---|---|
Summary: | Allow returning IDs in bulk_create with conflicts handling → Allow returning IDs in QuerySet.bulk_create() when updating conflicts. |
Triage Stage: | Unreviewed → Accepted |
follow-up: 3 comment:2 by , 17 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Sure I will.
comment:3 by , 17 months ago
Replying to Thomas C:
Sure I will.
Thanks. About tests, it should be enough to add some assertions to existing tests: _test_update_conflicts_two_fields()
, test_update_conflicts_unique_fields_pk()
, _test_update_conflicts_unique_two_fields()
, _test_update_conflicts()
, and test_update_conflicts_unique_fields_update_fields_db_column()
when connection.features.can_return_rows_from_bulk_insert
is True.
comment:5 by , 16 months ago
Triage Stage: | Accepted → Ready for checkin |
---|
Thanks for the ticket. I've checked and it works on PostgreSQL, MariaDB 10.5+, and SQLite 3.35+:
django/db/models/query.py
on_conflict is None:Would you like to prepare a patch via GitHub PR? (docs changes and tests are required)