Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support multi db atomic_requests #7739

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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