Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Fix set_rollback on @transaction.non_atomic_requests.
  • Loading branch information
hellysmile committed Jun 8, 2015
commit c292b3d1324eafd791290a61fd4883c9edd0b0cb
3 changes: 2 additions & 1 deletion rest_framework/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ def set_rollback():
if connection.settings_dict.get('ATOMIC_REQUESTS', False):
# If running in >=1.6 then mark a rollback as required,
# and allow it to be handled by Django.
transaction.set_rollback(True)
if connection.in_atomic_block:
transaction.set_rollback(True)
elif transaction.is_managed():
# Otherwise handle it explicitly if in managed mode.
if transaction.is_dirty():
Expand Down
34 changes: 33 additions & 1 deletion tests/test_atomic_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from django.db import connection, connections, transaction
from django.test import TestCase
from django.utils.decorators import method_decorator
from django.utils.unittest import skipUnless
from rest_framework import status
from rest_framework.exceptions import APIException
from rest_framework.exceptions import APIException, PermissionDenied
from rest_framework.response import Response
from rest_framework.test import APIRequestFactory
from rest_framework.views import APIView
Expand Down Expand Up @@ -32,6 +33,16 @@ def post(self, request, *args, **kwargs):
raise APIException


class NonAtomicAPIExceptionView(APIView):
@method_decorator(transaction.non_atomic_requests)
def dispatch(self, *args, **kwargs):
return super(NonAtomicAPIExceptionView, self).dispatch(*args, **kwargs)

def post(self, request, *args, **kwargs):
BasicModel.objects.create()
raise PermissionDenied


@skipUnless(connection.features.uses_savepoints,
"'atomic' requires transactions and savepoints.")
class DBTransactionTests(TestCase):
Expand Down Expand Up @@ -108,3 +119,24 @@ def test_api_exception_rollback_transaction(self):
self.assertEqual(response.status_code,
status.HTTP_500_INTERNAL_SERVER_ERROR)
assert BasicModel.objects.count() == 0


@skipUnless(connection.features.uses_savepoints,
"'atomic' requires transactions and savepoints.")
class NonAtomicDBTransactionAPIExceptionTests(TestCase):
def setUp(self):
self.view = NonAtomicAPIExceptionView.as_view()
connections.databases['default']['ATOMIC_REQUESTS'] = True

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

def test_api_exception_rollback_transaction_non_atomic_view(self):
request = factory.post('/')

response = self.view(request)

# without checking connection.in_atomic_block view raises 500
# due attempt to rollback without transaction
self.assertEqual(response.status_code,
status.HTTP_403_FORBIDDEN)