Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ATOMIC_REQUEST and Transactions in Django 1.6

Given the following code:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

From my understanding of transactions in Django 1.6 if do_stuff throws an exception, say an IntegrityError, then the transaction will be rolled back right. But since Django itself is calling the view nothing will stop the IntegrityError from rising up the call stack and causing an HTTP 500 error yes? Let's assume that's not what we want, as we want to gracefully handle the error, but still get the rollback functionality.

So I guess the obvious thought is well, don't do that, use transaction.atomic as a context manager that is wrapped in a try except block like the example here:

try:
    with transaction.atomic():
        generate_relationships()
except IntegrityError:
    handle_exception()

Fine. But then if you want to use the Transaction per HTTP Request functionality by setting ATOMIC_REQUEST = True in your db config, which means django will in effect just add the transaction.atomic decorate to your view, which won't catch any exceptions. How is ATOMIC_REQUEST even useful? Why would you ever want to let your Database errors propagate all the way up to the user?

So my question is.

  1. What am I missing here or is my understanding correct?
  2. If I'm correct what is a use case for using ATOMIC_REQUEST? Am I expected to write a urls.hadler500 or should I implement some middleware to catch the errors?
like image 601
j1z0 Avatar asked Dec 19 '13 13:12

j1z0


People also ask

What are transactions in Django?

A transaction is an atomic set of database queries. Even if your program crashes, the database guarantees that either all the changes will be applied, or none of them. Django doesn't provide an API to start a transaction.

How does Django handle concurrency?

When you run multiple workers of your Django application, you will run into concurrency issues when the same queryset is updated by different processes at the same time. To prevent this, use select_for_update inside a transaction block to fetch your queryset so that it is locked until the transaction is completed.

What is a transaction in DBMS?

What is a transaction DBMS? Transactions refer to a set of operations that are used for performing a set of logical work. Usually, a transaction means the data present in the DB has changed. Protecting the user data from system failures is one of the primary uses of DBMS.


1 Answers

Your understanding is correct. What you're missing is that letting exceptions propagate from your view code (which is quite different from "propagate all the way up to the user") is a perfectly normal thing to do in Django.

You can customize the resulting behavior by making a 500.html template, by overriding handler500, or by making your own custom middleware. In all of those standard cases, using ATOMIC_REQUESTS will do what you want it to do.

If you want to catch exceptions in your view code and handle them specially, you can certainly do that, you'll just have to specify how to handle transactions manually. Using ATOMIC_REQUESTS is just a way to save some boilerplate for the common case, while allowing you to customize the behavior yourself in the uncommon case.

like image 125
Kevin Christopher Henry Avatar answered Sep 30 '22 10:09

Kevin Christopher Henry