Skip to content

Commit de7468d

Browse files
authored
support multi db atomic_requests (#7739)
1 parent 8f6d2d2 commit de7468d

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy