Skip to content

Commit ed75118

Browse files
jmo-qapstefanacin
authored andcommitted
support multi db atomic_requests (encode#7739)
1 parent 8f6d2d2 commit ed75118

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

rest_framework/views.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44
from django.conf import settings
55
from django.core.exceptions import PermissionDenied
6-
from django.db import connection, models, transaction
6+
from django.db import connections, models
77
from django.http import Http404
88
from django.http.response import HttpResponseBase
99
from django.utils.cache import cc_delim_re, patch_vary_headers
@@ -63,9 +63,9 @@ def get_view_description(view, html=False):
6363

6464

6565
def set_rollback():
66-
atomic_requests = connection.settings_dict.get('ATOMIC_REQUESTS', False)
67-
if atomic_requests and connection.in_atomic_block:
68-
transaction.set_rollback(True)
66+
for db in connections.all():
67+
if db.settings_dict['ATOMIC_REQUESTS'] and db.in_atomic_block:
68+
db.set_rollback(True)
6969

7070

7171
def exception_handler(exc, context):

tests/conftest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def pytest_configure(config):
2424
'default': {
2525
'ENGINE': 'django.db.backends.sqlite3',
2626
'NAME': ':memory:'
27+
},
28+
'secondary': {
29+
'ENGINE': 'django.db.backends.sqlite3',
30+
'NAME': ':memory:'
2731
}
2832
},
2933
SITE_ID=1,

tests/test_atomic_requests.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,41 @@ def test_api_exception_rollback_transaction(self):
130130
assert BasicModel.objects.count() == 0
131131

132132

133+
@unittest.skipUnless(
134+
connection.features.uses_savepoints,
135+
"'atomic' requires transactions and savepoints."
136+
)
137+
class MultiDBTransactionAPIExceptionTests(TestCase):
138+
databases = '__all__'
139+
140+
def setUp(self):
141+
self.view = APIExceptionView.as_view()
142+
connections.databases['default']['ATOMIC_REQUESTS'] = True
143+
connections.databases['secondary']['ATOMIC_REQUESTS'] = True
144+
145+
def tearDown(self):
146+
connections.databases['default']['ATOMIC_REQUESTS'] = False
147+
connections.databases['secondary']['ATOMIC_REQUESTS'] = False
148+
149+
def test_api_exception_rollback_transaction(self):
150+
"""
151+
Transaction is rollbacked by our transaction atomic block.
152+
"""
153+
request = factory.post('/')
154+
num_queries = 4 if connection.features.can_release_savepoints else 3
155+
with self.assertNumQueries(num_queries):
156+
# 1 - begin savepoint
157+
# 2 - insert
158+
# 3 - rollback savepoint
159+
# 4 - release savepoint
160+
with transaction.atomic(), transaction.atomic(using='secondary'):
161+
response = self.view(request)
162+
assert transaction.get_rollback()
163+
assert transaction.get_rollback(using='secondary')
164+
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
165+
assert BasicModel.objects.count() == 0
166+
167+
133168
@unittest.skipUnless(
134169
connection.features.uses_savepoints,
135170
"'atomic' requires transactions and savepoints."

0 commit comments

Comments
 (0)