notbad.jpeg notbad.jpeg - 1 year ago 192
Python Question

django: Proper way to recover from IntegrityError

What's the proper way to recover from an
, or any other errors that could leave my transactions screwed up without using manual transaction control?

In my application, I'm running into problems with
s that I want to recover from, that screw up later database activity, leaving me with:

DatabaseError: current transaction is aborted, commands ignored until end of transaction block`

for all database activity after ignoring

This block of code should reproduce the error I'm seeing

from django.db import transaction

try: # Do a bad save that will raise IntegrityError
except IntegrityError:

MyModel.objects.all() # raises DatabaseError: current transaction is aborted, commands ignored until end of transaction block

According to the docs, the solution to recover from an
is by rolling back the transaction. But the following code results in a

from django.db import transaction

except IntegrityError:
transaction.rollback() # raises TransactionManagementError: This code isn't under transaction management

MyModel.objects.all() # Should work

EDIT: I'm confused by the message from the
, because if in my
I do a:


instead of the django
, the
succeeds, which doesn't make sense if my code "isn't under transaction management". It also doesn't make sense that code that isn't under transaction management (which I assume means it's using autocommit), can have transactions that span multiple queries.

EDIT #2: I'm aware of using manual transaction control to be able to recover from these errors, but shouldn't I be able to recover without manual transaction control? My understanding is that if I'm using autocommit, there should only be one write per transaction, so it should not affect later database activity.

EDIT #3: This is a couple years later, but in django 1.4 (not sure about later versions), another issue here was that
doesn't honor autocommit behavior.


  • Django: 1.4 (
    is not enabled)

  • Python: 2.7

  • Postgres: 9.1

Answer Source

Django's default commit mode is AutoCommit. In order to do rollback, you need to wrap the code doing the work in a transaction. [docs]

with transaction.commit_on_success():
    # Your code here. Errors will auto-rollback.

To get database level autocommit, you will require the following option in your DATABASES settings dictionary.

'OPTIONS': {'autocommit': True,}

Alternately, you can use explicit savepoints to roll back to. [docs]

def viewfunc(request):
  # open transaction now contains
  sid = transaction.savepoint()
  # open transaction now contains and

  if want_to_keep_b:
      # open transaction still contains and
      # open transaction now contains only

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download