Transaction error when Django REST Framework raises an error on purpose
Asked Answered
B

1

8

I have updated a project using Django REST Framework from a 2.x version to the last stable version (3.1.3). After fixing some deprecated uses in my serializers, I ran python manage.py test to make sure nothing have been broken.

Everything works fine except some of my tests where I am testing invalid REST requests (on purpose). For example:

def test_get_events_of_other_user(self):
    # Assume the setUp log the user1 with self.client 
    # and here, there is some code initializing an 
    # event for user2
    response = self.client.get("/event/123/")
    self.assertEqual(404, response.status_code)

The viewset generate a ORM-query like MyEventModel.objects.get(user=request.user, pk=123), which obviously raises a 404 exception in DRF, since no object should be returned here (I know, it should be a 403 to be REST-compliant...). But this raises a TransactionManagementError:

Traceback (most recent call last):
  [...]
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/rest_framework/viewsets.py", line 85, in view
    return self.dispatch(request, *args, **kwargs)
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/rest_framework/views.py", line 456, in dispatch
    response = self.handle_exception(exc)
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/rest_framework/views.py", line 421, in handle_exception
    response = exception_handler(exc, context)
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/rest_framework/views.py", line 81, in exception_handler
    set_rollback()
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/rest_framework/compat.py", line 277, in set_rollback
    transaction.set_rollback(True)
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/django/db/transaction.py", line 215, in set_rollback
    return get_connection(using).set_rollback(rollback)
  File "/my_virtual_env_path/local/lib/python2.7/site-packages/django/db/backends/__init__.py", line 372, in set_rollback
    "The rollback flag doesn't work outside of an 'atomic' block.")
TransactionManagementError: The rollback flag doesn't work outside of an 'atomic' block.

It looks like one of my middleware is doing some SQL query after the view, and hit the transaction closed by DRF, since the 3.1.3. The desired behaviour (i.e get a 404 NOT FOUND) works with the 3.1.2...

Does anyone has an idea of how I could avoid the rollback? Is it a misconception in DRF?

Boron answered 21/7, 2015 at 8:26 Comment(0)
T
2

This looks like a bug in DRF that has already been fixed. As you can see here they have changed the code so that it only rolls back when in an atomic block.

Since there is no newer version published, you could either apply the same fix to your installed code or use an earlier version until 3.1.3 is superseded.

Treachery answered 3/8, 2015 at 22:30 Comment(1)
Indeed, it works with this fix. I will continue to user the 3.1.2 release until the 3.1.4 is out. Thanks for the link!Boron

© 2022 - 2024 — McMap. All rights reserved.