Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python TransactionManagementError“;你可以';直到';结束时才执行查询;原子';块;使用信号时,但仅在单元测试期间_Python_Django_Unit Testing_Django Signals - Fatal编程技术网

Python TransactionManagementError“;你可以';直到';结束时才执行查询;原子';块;使用信号时,但仅在单元测试期间

Python TransactionManagementError“;你可以';直到';结束时才执行查询;原子';块;使用信号时,但仅在单元测试期间,python,django,unit-testing,django-signals,Python,Django,Unit Testing,Django Signals,在试图保存Django用户模型实例时,我遇到TransactionManagementError,在它的post_save信号中,我正在保存一些将用户作为外键的模型 上下文和错误与这个问题非常相似 但是,在这种情况下,只有在单元测试时才会发生错误 它在手动测试中运行良好,但单元测试失败 有什么我遗漏的吗 以下是代码片段: views.py @csrf_exempt def mobileRegister(request): if request.method == 'GET':

在试图保存Django用户模型实例时,我遇到TransactionManagementError,在它的post_save信号中,我正在保存一些将用户作为外键的模型

上下文和错误与这个问题非常相似

但是,在这种情况下,只有在单元测试时才会发生错误

它在手动测试中运行良好,但单元测试失败

有什么我遗漏的吗

以下是代码片段:

views.py

@csrf_exempt
def mobileRegister(request):
    if request.method == 'GET':
        response = {"error": "GET request not accepted!!"}
        return HttpResponse(json.dumps(response), content_type="application/json",status=500)
    elif request.method == 'POST':
        postdata = json.loads(request.body)
        try:
            # Get POST data which is to be used to save the user
            username = postdata.get('phone')
            password = postdata.get('password')
            email = postdata.get('email',"")
            first_name = postdata.get('first_name',"")
            last_name = postdata.get('last_name',"")
            user = User(username=username, email=email,
                        first_name=first_name, last_name=last_name)
            user._company = postdata.get('company',None)
            user._country_code = postdata.get('country_code',"+91")
            user.is_verified=True
            user._gcm_reg_id = postdata.get('reg_id',None)
            user._gcm_device_id = postdata.get('device_id',None)
            # Set Password for the user
            user.set_password(password)
            # Save the user
            user.save()
signal.py

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        company = None
        companycontact = None
        try:   # Try to make userprofile with company and country code provided
            user = User.objects.get(id=instance.id)
            rand_pass = random.randint(1000, 9999)
            company = Company.objects.get_or_create(name=instance._company,user=user)
            companycontact = CompanyContact.objects.get_or_create(contact_type="Owner",company=company,contact_number=instance.username)
            profile = UserProfile.objects.get_or_create(user=instance,phone=instance.username,verification_code=rand_pass,company=company,country_code=instance._country_code)
            gcmDevice = GCMDevice.objects.create(registration_id=instance._gcm_reg_id,device_id=instance._gcm_reg_id,user=instance)
        except Exception, e:
            pass
tests.py

class AuthTestCase(TestCase):
    fixtures = ['nextgencatalogs/fixtures.json']
    def setUp(self):
        self.user_data={
            "phone":"0000000000",
            "password":"123",
            "first_name":"Gaurav",
            "last_name":"Toshniwal"
            }

    def test_registration_api_get(self):
        response = self.client.get("/mobileRegister/")
        self.assertEqual(response.status_code,500)

    def test_registration_api_post(self):
        response = self.client.post(path="/mobileRegister/",
                                    data=json.dumps(self.user_data),
                                    content_type="application/json")
        self.assertEqual(response.status_code,201)
        self.user_data['username']=self.user_data['phone']
        user = User.objects.get(username=self.user_data['username'])
        # Check if the company was created
        company = Company.objects.get(user__username=self.user_data['phone'])
        self.assertIsInstance(company,Company)
        # Check if the owner's contact is the same as the user's phone number
        company_contact = CompanyContact.objects.get(company=company,contact_type="owner")
        self.assertEqual(user.username,company_contact[0].contact_number)
回溯:

======================================================================
ERROR: test_registration_api_post (nextgencatalogs.apps.catalogsapp.tests.AuthTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/nextgencatalogs/apps/catalogsapp/tests.py", line 29, in test_registration_api_post
    user = User.objects.get(username=self.user_data['username'])
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/manager.py", line 151, in get
    return self.get_queryset().get(*args, **kwargs)
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 301, in get
    num = len(clone)
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 77, in __len__
    self._fetch_all()
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 854, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 220, in iterator
    for row in compiler.results_iter():
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 710, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 781, in execute_sql
    cursor.execute(sql, params)
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/backends/util.py", line 47, in execute
    self.db.validate_no_broken_transaction()
  File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/backends/__init__.py", line 365, in validate_no_broken_transaction
    "An error occurred in the current transaction. You can't "
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

----------------------------------------------------------------------

我自己也遇到了同样的问题。这是由于Django的较新版本中处理事务的方式有点奇怪,再加上故意触发异常的unittest造成的

我有一个unittest,它检查以确保通过故意触发IntegrityError异常来强制执行唯一列约束:

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()
在Django 1.4中,这工作得很好。但是,在Django 1.5/1.6中,每个测试都包装在一个事务中,因此如果发生异常,它会中断事务,直到您显式回滚它。因此,该事务中的任何进一步ORM操作,如my
do\u more\u model\u stuff()
,都将失败,并出现
django.db.transaction.TransactionManagementError
异常

与评论中提到的caio一样,解决方案是使用
transaction.atomic
捕获异常,如:

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

这将防止故意抛出的异常破坏整个unittest的事务。

因为@mkoistinen从未给出过答案,所以我将发布他的建议,这样人们就不必仔细阅读评论了

考虑将您的测试类声明为TransactionTestCase,而不仅仅是TestCase

从:TransactionTestCase可以调用commit和rollback,并观察这些调用对数据库的影响。

我也有同样的问题

就我而言,我是这样做的

author.tasks.add(tasks)
所以把它转换成

author.tasks.add(*tasks)

已删除该错误。

我在使用django 1.9.7运行create_test_数据函数的单元测试时遇到此错误。它在django的早期版本中工作

看起来是这样的:

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()

我也有同样的问题,但是transaction.atomic()和TransactionTestCase对我来说不起作用

python manage.py test-r
而不是
python manage.py test
对我来说是可以的,也许执行顺序很关键

然后我找到一个文档,它提到了哪个测试将首先运行


所以,我使用TestCase进行数据库交互,
unittest.TestCase
进行其他简单的测试,它现在可以工作了

对我来说,建议的修复方案不起作用。在我的测试中,我使用
Popen
打开一些子流程来分析/lint迁移(例如,一个测试检查是否没有模型更改)

对我来说,从
SimpleTestCase
而不是
TestCase
进行子类化确实起到了作用

请注意,
SimpleTestCase
不允许使用数据库


虽然这并没有回答最初的问题,但我希望这能帮助一些人。

关于@kdazzle的答案是正确的。我没有尝试它,因为人们说“Django的TestCase类是TransactionTestCase的一个更常用的子类”,所以我认为这两种用法是一样的。但该公司对此做出了更好的解释:

TestCase类将测试包装在两个嵌套的atomic()块中: 全班一人,每次考试一人。这就是 应使用TransactionTestCase。它不使用 atomic()块,因此您可以测试需要 没有任何问题的交易

编辑:没有用,我想是的,但是没有


如果使用pytest django,您可以将
transaction=True
传递给
django_db
装饰程序,以避免此错误,在4年内他们可以修复此问题

Django本身有TransactionTestCase,它允许您进行测试 事务,并将在测试之间刷新数据库以隔离 他们。这样做的缺点是,由于需要刷新数据库,这些测试的设置速度要慢得多。pytest django还支持这种类型的测试,您可以使用django_db标记的参数来选择:


根据对这个问题的回答,下面是另一种方法:

with transaction.atomic():
    self.assertRaises(IntegrityError, models.Question.objects.create, **{'domain':self.domain, 'slug':'barks'})

在我的例子中,它是由原因引起的,但没有调用
super().tearDownClass()


从文档中可以看出:“另一方面,TestCase不会在测试后截断表。相反,它将测试代码封装在测试结束时回滚的数据库事务中。显式提交(如transaction.commit())和隐式提交(可能由transaction.atomic()引起)替换为nop操作。这保证了测试结束时的回滚将数据库恢复到其初始状态。有这样一个IntegrityError异常“try:…除了IntegrityError:…”我要做的是在try块中使用transaction.atomic:“try:with transaction.atomic():…除了IntegrityError:…”现在一切正常。然后在“尝试/Butter块”中搜索“包装原子”,允许对完整性错误进行自然处理:“也可以将测试类声明为事务性测试用例,而不仅仅是TestCase.哦,我从另一个文档中找到了相关文档。文档是。对我来说,我已经有了一个
transaction.atomic()
块,但是我得到了这个错误,我不知道为什么。我采纳了这个答案的建议,在我的原子块内的故障区域周围放置了一个嵌套的原子块。之后,它给出了我遇到的完整性错误的详细错误,允许我修复代码并执行我试图执行的操作。@mkoistinen

@pytest.mark.django_db(transaction=True)
def test_spam():
    pass  # test relying on transactions
with transaction.atomic():
    self.assertRaises(IntegrityError, models.Question.objects.create, **{'domain':self.domain, 'slug':'barks'})
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
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()