mirror of
https://github.com/django/django.git
synced 2025-08-17 17:20:38 +00:00
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.
This commit is contained in:
parent
d70b4bea18
commit
d35ce682e3
2 changed files with 30 additions and 2 deletions
|
@ -3,13 +3,15 @@ import datetime
|
|||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import F
|
||||
from django.db.models.functions import Lower
|
||||
from django.test import TestCase, skipUnlessDBFeature
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase, override_settings, skipUnlessDBFeature
|
||||
|
||||
from .models import (
|
||||
Article,
|
||||
CustomDbColumn,
|
||||
CustomPk,
|
||||
Detail,
|
||||
Food,
|
||||
Individual,
|
||||
JSONFieldNullable,
|
||||
Member,
|
||||
|
@ -25,6 +27,11 @@ from .models import (
|
|||
)
|
||||
|
||||
|
||||
class WriteToOtherRouter:
|
||||
def db_for_write(self, model, **hints):
|
||||
return "other"
|
||||
|
||||
|
||||
class BulkUpdateNoteTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
@ -107,6 +114,8 @@ class BulkUpdateNoteTests(TestCase):
|
|||
|
||||
|
||||
class BulkUpdateTests(TestCase):
|
||||
databases = {"default", "other"}
|
||||
|
||||
def test_no_fields(self):
|
||||
msg = "Field names must be given to bulk_update()."
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
|
@ -302,3 +311,20 @@ class BulkUpdateTests(TestCase):
|
|||
parent.refresh_from_db()
|
||||
self.assertEqual(parent.f, 42)
|
||||
self.assertIsNone(parent.single)
|
||||
|
||||
@override_settings(DATABASE_ROUTERS=[WriteToOtherRouter()])
|
||||
def test_database_routing(self):
|
||||
note = Note.objects.create(note="create")
|
||||
note.note = "bulk_update"
|
||||
with self.assertNumQueries(1, using="other"):
|
||||
Note.objects.bulk_update([note], fields=["note"])
|
||||
|
||||
@override_settings(DATABASE_ROUTERS=[WriteToOtherRouter()])
|
||||
def test_database_routing_batch_atomicity(self):
|
||||
f1 = Food.objects.create(name="Banana")
|
||||
f2 = Food.objects.create(name="Apple")
|
||||
f1.name = "Kiwi"
|
||||
f2.name = "Kiwi"
|
||||
with self.assertRaises(IntegrityError):
|
||||
Food.objects.bulk_update([f1, f2], fields=["name"], batch_size=1)
|
||||
self.assertIs(Food.objects.filter(name="Kiwi").exists(), False)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue