Opened 2 years ago
Closed 2 years 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 , 2 years 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 |
comment:3 by , 2 years 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 , 2 years 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)