Django / sqlite3“OperationalError:没有这样的表”关于线程操作

Posted

技术标签:

【中文标题】Django / sqlite3“OperationalError:没有这样的表”关于线程操作【英文标题】:Django/sqlite3 "OperationalError: no such table" on threaded operation 【发布时间】:2016-04-12 00:36:26 【问题描述】:

根据我在文档中阅读的所有内容,Django 和 py-sqlite3 都应该可以使用线程访问。 (对吗?)但是这个代码 sn-p 对我来说失败了。主线程中的操作有效,但在我创建的线程中无效。我得到了:

文件 "C:\Python27\lib\site-packages\django-1.9-py2.7.egg\django\db\backends\sq lite3\base.py",第 323 行,在执行中 return Database.Cursor.execute(self, query, params)

OperationalError:没有这样的表:thrtest_mymodel

有什么问题?

我该如何准确追踪 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()

更新:这是来自 settings.py 的数据库:

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

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

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

【问题讨论】:

你的数据库设置是什么样的? 这似乎是相关的,尽管它似乎在 1.8.x 和 1.9.x 中已修复。 code.djangoproject.com/ticket/12118 【参考方案1】:

像这样更改您的DATABASES

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

这将强制 django 在磁盘上创建一个真正的 sqlite 数据库,而不是在内存中创建它。

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

【讨论】:

感谢您的回答。但这是我尝试过的配置之一(上面的最后一次更新——旧 django 版本使用 'TEST_NAME' 与 'TEST':'NAME': ...)。仅检查某些内容并完成所有工作的测试都可以正常工作,但是我的多线程测试在中间突然运行了一段时间,会通知数据库已更改,并且所有表都已消失。就像数据库自动回滚一样。 strange :/ 作为最后一个选项,您可以说 django 在测试后使用--keepdb 键保留数据库。 添加后出现新异常:“数据库已锁定”

以上是关于Django / sqlite3“OperationalError:没有这样的表”关于线程操作的主要内容,如果未能解决你的问题,请参考以下文章

sqlite3常用命令以及django如何操作sqlite3数据库

Django - 没有名为 _sqlite3 的模块

django:sqlite3.OperationalError:没有这样的表

Django 升级sqlite3

Django 升级sqlite3

Django 数据库迁移错误(sqlite3->postgre)