TransactionManagementError You can't execute queries until the end of the 'atomic' block while using signals, but only during Unit Testing
I ran into this same problem myself. This is caused by a quirk in how transactions are handled in the newer versions of Django coupled with a unittest that intentionally triggers an exception.
I had a unittest that checked to make sure a unique column constraint was enforced by purposefully triggering an IntegrityError exception:
def test_constraint(self):
try:
# Duplicates should be prevented.
models.Question.objects.create(domain=self.domain, slug='barks')
self.fail('Duplicate question allowed.')
except IntegrityError:
pass
do_more_model_stuff()
In Django 1.4, this works fine. However, in Django 1.5/1.6, each test is wrapped in a transaction, so if an exception occurs, it breaks the transaction until you explicitly roll it back. Therefore, any further ORM operations in that transaction, such as my do_more_model_stuff()
, will fail with that django.db.transaction.TransactionManagementError
exception.
Like caio mentioned in the comments, the solution is to capture your exception with transaction.atomic
like:
from django.db import transaction
def test_constraint(self):
try:
# Duplicates should be prevented.
with transaction.atomic():
models.Question.objects.create(domain=self.domain, slug='barks')
self.fail('Duplicate question allowed.')
except IntegrityError:
pass
That will prevent the purposefully-thrown exception from breaking the entire unittest's transaction.
Django test: TransactionManagementError: You can't execute queries until the end of the 'atomic' block
Apparently, moving from django.test.TestCase
to django.test.TransactionTestCase
solved the issue. Here are some important points regarding the differences between django.test.TestCase
and django.test.TransactionTestCase
:
TransactionTestCase
andTestCase
are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback:
TransactionTestCase
resets the database after the test runs by truncating all tables. ATransactionTestCase
may call commit and rollback and observe the effects of these calls on the database.A
TestCase
, on the other hand, does not truncate tables after a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. This guarantees that the rollback at the end of the test restores the database to its initial state.
Here you can find more details from the docs TransactionTestCase
An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block
From docs:
Avoid catching exceptions inside atomic!
Since the function had multiple nested try and excepts, I inserted another transaction.atomic()
within a the try and except closest to where the error is occurring.
Per docs, have nested try and excepts could complicate the initial atomic. I found that placing the atomic (for a second time) helps. Hope this helps others facing a similar situation.
try:
item_to_group_keys = []
promo_key = 'promo:' + str(request.user.id)
with connection.cursor() as cursor:
with transaction.atomic():
// more code here...
try:
with transaction.atomic(): // **added second atomic**
//more code
except:
pass
except IntegrityError:
Can't execute queries until end of atomic block in my data migration on django 1.7
This is similar to the example in the docs.
First, add the required import if you don't have it already.
from django.db import transaction
Then wrap the code that might raise an integrity error in an atomic block.
try:
with transaction.atomic():
inst.new_col = new_col_mapping[c]
inst.save()
except IntegrityError:
inst.delete()
The reason for the error is explained in the warning block 'Avoid catching exceptions inside atomic!' in the docs. Once Django encounters a database error, it will roll back the atomic block. Attempting any more database queries will cause a TransactionManagementError
, which you are seeing. By wrapping the code in an atomic block, only that code will be rolled back, and you can execute queries outside of the block.
Related Topics
How to Efficiently Handle European Decimal Separators Using the Pandas Read_CSV Function
Python Create Unix Timestamp Five Minutes in the Future
Generating Discrete Random Variables with Specified Weights Using Scipy or Numpy
Convert List into a Dictionary
Remove All Line Breaks from a Long String of Text
How to Merge Multiple Lists into One List in Python
Pyplot Move Alternative Y Axis to Background
Attributeerror: 'Client' Object Has No Attribute 'Send_Message' (Discord Bot)
Exponentials in Python: X**Y VS Math.Pow(X, Y)
How to Make the Width of the Title Box Span the Entire Plot
Sort Multidimensional Array Based on 2Nd Element of the Subarray
How to Install the Yaml Package for Python
How to Straighten a Rotated Rectangle Area of an Image Using Opencv in Python