关于线程操作的Django / sqlite3“OperationalError:no such table”

时间:2022-06-12 00:26:57

By everything I read in the docs, both Django and py-sqlite3 should be fine with threaded access. (Right?) But this code snippet fails for me. The operations in the main thread work, but not in the thread(s) I create. There I get:

通过我在文档中阅读的所有内容,Django和py-sqlite3都可以使用线程访问。 (对吗?)但是这段代码片段对我失败了。主线程中的操作有效,但不在我创建的线程中。在那里我得到:

File "C:\Python27\lib\site-packages\django-1.9-py2.7.egg\django\db\backends\sq lite3\base.py", line 323, in execute return Database.Cursor.execute(self, query, params)

文件“C:\ Python27 \ lib \ site-packages \ django-1.9-py2.7.egg \ django \ db \ backends \ sq lite3 \ base.py”,第323行,在执行返回Database.Cursor.execute(self ,查询,参数)

OperationalError: no such table: thrtest_mymodel

OperationalError:没有这样的表:thrtest_mymodel

What's the problem?

有什么问题?

How do I go about tracking down exactly what's happening to patch Django or whatever's necessary to fix it? The point of failure in Django is pretty indimidating. I can't tell how to see what tables it DOES see, or what differences to look for between main and other threads.

我如何准确地追踪修补Django的正在发生的事情或修复它的必要性? Django的失败点非常难以理解。我不知道如何查看它看到的表,或主要线程和其他线程之间要查找的差异。

from django.db import models

# Super-simple model
class MyModel(models.Model):
    message       = models.CharField('Message', max_length=200, blank=True)

#Test
from django.test import TestCase

import time
import threading
import random


done = threading.Event()
nThreads = 1


def InsertRec(msg):
    rec = MyModel.objects.create(message=msg)
    rec.save()


def InsertThread():
    try:
        msgNum = 1
        thrName = threading.currentThread().name
        print 'Starting %s' % thrName
        while not done.wait(random.random() * 0.1):
            msgNum += 1
            msg = '%s: %d' % (thrName, msgNum)
            print msg
            InsertRec(msg)
    finally:
        done.set()
    pass


class ThreadTestRun(TestCase):

    def testRunIt(self):
        nThisThread = 10
        msgSet = set()
        for x in xrange(nThisThread):
            msg = 'Some message %d' % x
            InsertRec(msg) # From main thread: works!
            msgSet.add(msg)
        self.assertEqual(MyModel.objects.count(), nThisThread)
        # We use sets because .all() doesn't preserve the original order.
        self.assertEqual(msgSet, set([r.message for r in MyModel.objects.all()]))
        thrSet = set()
        for thrNum in xrange(nThreads):
            t = threading.Thread(name='Thread %d' % thrNum, target=InsertThread)
            t.start()
            thrSet.add(t)

        done.wait(10.)
        done.set()
        for t in thrSet:
            t.join()

Update: Here is DATABASES from settings.py:

更新:这是来自settings.py的DATABASES:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:', # os.path.join(BASE_DIR, 'db.sqlite3'),
        'TEST_NAME' : ':memory:',
    },
}

Update: With respect to Django's ticket #12118, I get the same symptoms using ':memory:' or a disk file (for TEST_NAME).

更新:关于Django的票#12118,我使用':memory:'或磁盘文件(对于TEST_NAME)得到相同的症状。

Django 1.9, Python 2.7.11. (Same symptoms in Django 1.6.)

Django 1.9,Python 2.7.11。 (Django 1.6中的症状相同。)

1 个解决方案

#1


3  

Change your DATABASES like this:

像这样更改您的DATABASES:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
        'TEST' : 
            {
                'NAME': 'test_db',
            }
    },
}

This will force django to create a real sqlite db on the disk, instead of creating it in memory.

这将迫使django在磁盘上创建一个真正的sqlite db,而不是在内存中创建它。

Also be sure to inherit your test cases related to threading from django.test.testcases.TransactionTestCase. If you don't do so, the threads won't see database changes made from another threads.

还要确保从django.test.testcases.TransactionTestCase继承与线程相关的测试用例。如果不这样做,线程将不会看到从其他线程进行的数据库更改。

#1


3  

Change your DATABASES like this:

像这样更改您的DATABASES:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
        'TEST' : 
            {
                'NAME': 'test_db',
            }
    },
}

This will force django to create a real sqlite db on the disk, instead of creating it in memory.

这将迫使django在磁盘上创建一个真正的sqlite db,而不是在内存中创建它。

Also be sure to inherit your test cases related to threading from django.test.testcases.TransactionTestCase. If you don't do so, the threads won't see database changes made from another threads.

还要确保从django.test.testcases.TransactionTestCase继承与线程相关的测试用例。如果不这样做,线程将不会看到从其他线程进行的数据库更改。