Skip to content

Commit

Permalink
support multi db atomic_requests (encode#7739)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmo-qap authored and stefanacin committed Mar 22, 2021
1 parent 8f6d2d2 commit ed75118
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
8 changes: 4 additions & 4 deletions rest_framework/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db import connection, models, transaction
from django.db import connections, models
from django.http import Http404
from django.http.response import HttpResponseBase
from django.utils.cache import cc_delim_re, patch_vary_headers
Expand Down Expand Up @@ -63,9 +63,9 @@ def get_view_description(view, html=False):


def set_rollback():
atomic_requests = connection.settings_dict.get('ATOMIC_REQUESTS', False)
if atomic_requests and connection.in_atomic_block:
transaction.set_rollback(True)
for db in connections.all():
if db.settings_dict['ATOMIC_REQUESTS'] and db.in_atomic_block:
db.set_rollback(True)


def exception_handler(exc, context):
Expand Down
4 changes: 4 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def pytest_configure(config):
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'
},
'secondary': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'
}
},
SITE_ID=1,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_atomic_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,41 @@ def test_api_exception_rollback_transaction(self):
assert BasicModel.objects.count() == 0


@unittest.skipUnless(
connection.features.uses_savepoints,
"'atomic' requires transactions and savepoints."
)
class MultiDBTransactionAPIExceptionTests(TestCase):
databases = '__all__'

def setUp(self):
self.view = APIExceptionView.as_view()
connections.databases['default']['ATOMIC_REQUESTS'] = True
connections.databases['secondary']['ATOMIC_REQUESTS'] = True

def tearDown(self):
connections.databases['default']['ATOMIC_REQUESTS'] = False
connections.databases['secondary']['ATOMIC_REQUESTS'] = False

def test_api_exception_rollback_transaction(self):
"""
Transaction is rollbacked by our transaction atomic block.
"""
request = factory.post('/')
num_queries = 4 if connection.features.can_release_savepoints else 3
with self.assertNumQueries(num_queries):
# 1 - begin savepoint
# 2 - insert
# 3 - rollback savepoint
# 4 - release savepoint
with transaction.atomic(), transaction.atomic(using='secondary'):
response = self.view(request)
assert transaction.get_rollback()
assert transaction.get_rollback(using='secondary')
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
assert BasicModel.objects.count() == 0


@unittest.skipUnless(
connection.features.uses_savepoints,
"'atomic' requires transactions and savepoints."
Expand Down

0 comments on commit ed75118

Please sign in to comment.