339👍
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.
63👍
Since @mkoistinen never made their comment an answer, I’ll post the suggestion so people won’t have to dig through comments.
consider just declaring your test class as a TransactionTestCase rather than just TestCase.
From the Django docs: A TransactionTestCase may call commit and rollback and observe the effects of these calls on the database.
- [Django]-How can I create a deep clone of a DB object in Django?
- [Django]-Rendering a value as text instead of field inside a Django Form
- [Django]-Serializer call is showing an TypeError: Object of type 'ListSerializer' is not JSON serializable?
24👍
If using pytest-django you can pass transaction=True
to the django_db
decorator to avoid this error.
See https://pytest-django.readthedocs.io/en/latest/database.html#testing-transactions
Django itself has the TransactionTestCase which allows you to test
transactions and will flush the database between tests to isolate
them. The downside of this is that these tests are much slower to set up due to the required flushing of the database. pytest-django also supports this style of tests, which you can select using an argument to the django_db mark:
@pytest.mark.django_db(transaction=True)
def test_spam():
pass # test relying on transactions
- [Django]-Django: list all reverse relations of a model
- [Django]-Difference between User.objects.create_user() vs User.objects.create() vs User().save() in django
- [Django]-How to get superuser details in Django?
12👍
Here is another way to do it, based on the answer to this question:
with transaction.atomic():
self.assertRaises(IntegrityError, models.Question.objects.create, **{'domain':self.domain, 'slug':'barks'})
- [Django]-How do I get the object if it exists, or None if it does not exist in Django?
- [Django]-Django datetime issues (default=datetime.now())
- [Django]-Django models: default value for column
2👍
In my case it was caused but not calling super().tearDownClass()
class TnsFileViewSetTestCase(APITestCase):
@classmethod
def tearDownClass(self):
super().tearDownClass() # without this line we will get TransactionManagementError
for tnsfile in TnsFile.objects.all():
tnsfile.file.delete()
- [Django]-Macros in django templates
- [Django]-Passing STATIC_URL to file javascript with django
- [Django]-Visual Editor for Django Templates?
1👍
I have the same issue, but with transaction.atomic()
and TransactionTestCase
didn’t work for me.
python manage.py test -r
instead of python manage.py test
is ok for me, maybe the order of execution is crucial
then i find a doc about Order in which tests are executed, It mentions which test will run first.
So, I use TestCase for database interaction, unittest.TestCase
for other simple test, it works now!
- [Django]-Error: No module named staticfiles
- [Django]-POST jQuery array to Django
- [Django]-How can I get the full/absolute URL (with domain) in Django?
1👍
For me, the proposed fixes did not work. In my tests, I open some subprocesses with Popen
to analyze/lint migrations (e.g. one test checks if there are no model changes).
For me, subclassing from SimpleTestCase
instead of TestCase
did do the trick.
Note that SimpleTestCase
doesn’t allow to use the database.
While this does not answer the original question, I hope this helps some people anyway.
- [Django]-Django – iterate number in for loop of a template
- [Django]-How to server HTTP/2 Protocol with django
- [Django]-Is it bad to have my virtualenv directory inside my git repository?
1👍
def test_wrong_user_country_db_constraint(self):
"""
Check whether or not DB constraint doesnt allow to save wrong country code in DB.
"""
self.test_user_data['user_country'] = 'XX'
expected_constraint_name = "country_code_within_list_of_countries_check"
with transaction.atomic():
with self.assertRaisesRegex(IntegrityError, expected_constraint_name) as cm:
get_user_model().objects.create_user(**self.test_user_data)
self.assertFalse(
get_user_model().objects.filter(email=self.test_user_data['email']).exists()
)
with transaction.atomic() seems do the job correct
- [Django]-Django/DRF – 405 Method not allowed on DELETE operation
- [Django]-Embedding JSON objects in script tags
- [Django]-Referencing multiple submit buttons in django
1👍
class Pricing(models.Model):
price = models.DecimalField(max_digits=4, decimal_places=1)
is_active = models.BooleanField(default=False)
def __str__(self):
return str(self.price)
class Services(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=30)
pricing = models.OneToOneField(Pricing, on_delete=models.CASCADE, default=0.0)
categories = models.ManyToManyField(Category, related_name="services")
is_active = models.BooleanField(default=False)
def __str__(self):
return self.name
In my case you are getting this error in the function where you are testing an instance onetoonefield : where you’re creating a price instance and adding it into 2 service instances and getting this error:
Solution : Inside your function do this
with transaction.atomic():
with self.assertRaises(IntegrityError):
service = Services.objects.create(name = "Some Service", pricing= self.pricing1)
- [Django]-Using JSON in django template
- [Django]-Django: Open uploaded file while still in memory; In the Form Clean method?
- [Django]-How to deal with "SubfieldBase has been deprecated. Use Field.from_db_value instead."
0👍
I was getting this error on running unit tests in my create_test_data function using django 1.9.7. It worked in earlier versions of django.
It looked like this:
cls.localauth,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeLA, name='LA for test', email_general='test@test.com', address='test', postcode='test', telephone='test')
cls.chamber,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeC, name='chamber for test', email_general='test@test.com', address='test', postcode='test', telephone='test')
cls.lawfirm,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeL, name='lawfirm for test', email_general='test@test.com', address='test', postcode='test', telephone='test')
cls.chamber.active = True
cls.chamber.save()
cls.localauth.active = True
cls.localauth.save() <---- error here
cls.lawfirm.active = True
cls.lawfirm.save()
My solution was to use update_or_create instead:
cls.localauth,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeLA, name='LA for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})
cls.chamber,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeC, name='chamber for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})
cls.lawfirm,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeL, name='lawfirm for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})
- [Django]-How to manage local vs production settings in Django?
- [Django]-How do I do an OR filter in a Django query?
- [Django]-How can I activate the unaccent extension on an already existing model
0👍
The answer of @kdazzle is correct. I didnt try it because people said that ‘Django’s TestCase class is a more commonly used subclass of TransactionTestCase’ so I thought it was the same use one or another. But the blog of Jahongir Rahmonov explained it better:
the TestCase class wraps the tests within two nested atomic() blocks:
one for the whole class and one for each test. This is where
TransactionTestCase should be used. It does not wrap the tests with
atomic() block and thus you can test your special methods that require
a transaction without any problem.
EDIT: It didn’t work, I thought yes, but NO.
In 4 years they could fixed this…………………………………
- [Django]-How can I create a deep clone of a DB object in Django?
- [Django]-Django – how to unit test a post request using request.FILES
- [Django]-What's the best way to extend the User model in Django?
0👍
If you wanna perform multiple queries, this is the way to do it
@pytest.mark.django_db
def test_multiple queries_where_one_fails():
# Double transaction wrap is needed
with transaction.atomic():
# do a process with some failing query
with transaction.atomic():
assert Model.objects.count() == 0
# rest of assertions
- [Django]-Filtering dropdown values in django admin
- [Django]-Django-rest-framework returning 403 response on POST, PUT, DELETE despite AllowAny permissions
- [Django]-Django limit_choices_to for multiple fields with "or" condition
-2👍
I had the same issue.
In My Case I was doing this
author.tasks.add(tasks)
so converting it to
author.tasks.add(*tasks)
Removed that error.
- [Django]-Django aggregate or annotate
- [Django]-Django south migration – Adding FULLTEXT indexes
- [Django]-Django – how to visualize signals and save overrides?