Django: @transaction.commit_manually and accessing db from template


Posted:   |  More posts about python django db transaction

Bumped into this issue twice and because the first time it happened was almost a year ago, in different project, I'd already lost my mental note about it when it happened again for second time. Our views functions are wrapped inside @transaction.commit_manually, which look like below:-

@transaction.commit_manually
def send_message(request):
    context = {}
    # do some stuff
    transaction.commit()
    return render(request, 'path/to/template.html', context)

This work flawlessly until recently, I need to add some logic in the template that need to check certain user's permission, before displaying the part. In the template, it just some function call that access db like:-

{% if user.can_see_this %}
<a href="#">Some link</a>
{% endif %}

Django now raise TransactionManagementError complaining I have pending commit/rollback. It doesn't make sense because I can verify that the line that executed transaction.commit() was reached in the views above. Only after reading through this ticket on django issue tracker, I'd immediately remember the real issue.

Turn out this caused by new behavior of django transaction in 1.3 and above. Before 1.3, transaction only marked as dirty if we did any write database operation but since 1.3 and above, any database operation will mark the transaction as dirty. So the following code will work before 1.3:-

@transaction.commit_manually
def sendmessage(request):
    transaction.rollback()
    user = User.objects.get(pk=1)
    return HttpResponse('OK')

All database operation now will mark the transaction as dirty and since we access the db in template - which happened during render after we called commit(), it obvious now why django complain we unclosed transaction.

It should be written like below:-

@transaction.commit_manually
def send_message(request):
    context = {}
    # do some stuff
    response = render(request, 'path/to/template.html', context)
    transaction.commit()
    return response
Comments powered by Disqus

About me

Web developer in Malaysia. Currently work at MARIMORE Inc building internet services using Python and Django web framework.

ImportError is an error message emitted by Python when it failed to load certain module as requested by programmer. It's a very common error when someone new to the language trying it out. This website on the same theme, will try provide help for newcomers on any technologies to overcome their first hurdle.

Try most of the examples you may find here on Digital Ocean cloud service. They provide excellent VPS at a very cheaper price. Using this referral link you'll get USD10 credits upon sign up. That's enough to run single VPS with 1GB RAM for a month.

Others

I can also be found at the following sites:-

  • http://k4ml.blogspot.com/
  • http://k4ml.github.io/
  • http://metak4ml.blogspot.com/
  • http://www.mydev.my/
  • http://github.com/k4ml/

Disclaimers

The postings on this site are my own and don't necessarily represent my employer's positions, strategies or opinions.

Share