summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2022-02-09 01:34:45 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-02-09 11:14:50 +0100
commitd35ce682e31ea4a86c2079c60721fae171f03d7c (patch)
treeef28db03ec81c0d5835e0ff34d49099fbd7b80c9 /django
parentd70b4bea18c96e518ce14dca96085e9265e8ebb6 (diff)
Fixed #33506 -- Made QuerySet.bulk_update() perform atomic writes against write database.
The lack of _for_write = True assignment in bulk_update prior to accessing self.db resulted in the db_for_read database being used to wrap batched UPDATEs in a transaction. Also tweaked the batch queryset creation to also ensure they are executed against the same database as the opened transaction under all circumstances. Refs #23646, #33501.
Diffstat (limited to 'django')
-rw-r--r--django/db/models/query.py4
1 files changed, 3 insertions, 1 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index aa10176dc0..0cebcc70d6 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -725,6 +725,7 @@ class QuerySet:
)
# PK is used twice in the resulting update query, once in the filter
# and once in the WHEN. Each field will also have one CAST.
+ self._for_write = True
connection = connections[self.db]
max_batch_size = connection.ops.bulk_batch_size(["pk", "pk"] + fields, objs)
batch_size = min(batch_size, max_batch_size) if batch_size else max_batch_size
@@ -746,9 +747,10 @@ class QuerySet:
update_kwargs[field.attname] = case_statement
updates.append(([obj.pk for obj in batch_objs], update_kwargs))
rows_updated = 0
+ queryset = self.using(self.db)
with transaction.atomic(using=self.db, savepoint=False):
for pks, update_kwargs in updates:
- rows_updated += self.filter(pk__in=pks).update(**update_kwargs)
+ rows_updated += queryset.filter(pk__in=pks).update(**update_kwargs)
return rows_updated
bulk_update.alters_data = True