Django Transaction managed block ended with pendin

2019-06-26 06:35发布

I have a view function which needs to be manually transaction managed, but when I apply the @transaction.commit_manually decorator, django ALWAYS raises the below exception.

As you can see from the code trace below, the transaction is committed right before return from the view.

I am using sqlite, both on windows and linux, with django 1.4.

The following is the output of django_trace, followed by the exception. To be clear: this happens whether or not I use django_trace, and when there are no decorators, no exception whatsoever is raised. This is not being caused by a "swallowed" exception.

Note that line 60 in the below is inside a context processor, and hence outside of the commit_manually-wrapped view.

01->mainapp.views:1321:         transaction.commit()
01->mainapp.views:1322:         return render_to_response('mainapp/templates/incorporate.html',
01->mainapp.views:1323:                                       RequestContext(request, form_params))
02-->mainapp.views:60:     transaction.rollback_unless_managed()
02-->mainapp.views:61:     return {'home_login_form': AuthenticationForm(request)}
Traceback (most recent call last):
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\contrib\staticfiles\handlers.py", line 67, in __call__
    return self.application(environ, start_response)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\contrib\staticfiles\handlers.py", line 67, in __call__
    return self.application(environ, start_response)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\core\handlers\wsgi.py", line 241, in __call__
    response = self.get_response(request)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\core\handlers\base.py", line 179, in get_response
    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\core\handlers\base.py", line 221, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\core\handlers\base.py", line 111, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Marcin\Documents\oneclickcos\oneclickcos\mainapp\decorators.py", line 26, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\db\transaction.py", line 209, in inner
    return func(*args, **kwargs)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\db\transaction.py", line 203, in __exit__
    self.exiting(exc_value, self.using)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\db\transaction.py", line 288, in exiting
    leave_transaction_management(using=using)
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\db\transaction.py", line 52, in leave_transaction_management
    connection.leave_transaction_management()
  File "C:\Users\Marcin\Documents\oneclickcos\lib\site-packages\django\db\backends\__init__.py", line 119, in leave_transaction_management
    raise TransactionManagementError("Transaction managed block ended with "
TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK

To be clear, I have checked the other questions on this topic, and they DO NOT have the solution to my problem.

3条回答
The star\"
2楼-- · 2019-06-26 07:16

Refs the doc

If your view changes data and doesn't commit() or rollback(), Django will raise a TransactionManagementError exception.

So you have change in transaction, and need a rollback or commit before the last return. transaction.rollback_unless_managed() will not work because transaction inside commit_manually is managed.

查看更多
我想做一个坏孩纸
3楼-- · 2019-06-26 07:24

It turns out that during template rendering, there was database access, so the usual pattern like:

return render_to_response('mainapp/templates/incorporate.html',
                          RequestContext(request, form_params))

was the cause of the problem. I needed to replace that with:

retval = render_to_response('mainapp/templates/incorporate.html',
                                      RequestContext(request, form_params))
transaction.commit()
return retval

In addition, other SO answers reveal that the transaction management decorators hide all exceptions and instead raise the transaction management exception. Unfortunately, the easiest way to diagnose this is to run without the decorator, and see if an exception is occurring, or wrap your whole view in a try/except.

查看更多
冷血范
4楼-- · 2019-06-26 07:36

I had this problem and solved it by decorating the context processor with transaction.commit_on_success eg

@transaction.commit_manually
def my_view(request):
    ...
    transaction.commit()
    return render_to_response("template.html", context_instance=RequestContext(request, my_ctx))


@transaction.commit_on_success
def my_context_processor(request):
    ...

Even db reads require a commit/rollback (including those inside a context processor) https://docs.djangoproject.com/en/dev/topics/db/transactions/#requirements-for-transaction-handling

查看更多
登录 后发表回答