Django 测试:临时数据库文件中没有数据

7 投票
5 回答
3896 浏览
提问于 2025-04-17 13:07

我在 settings.py 中设置了一个 sqlite3 数据库,具体如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.spatialite',
        'NAME': 'path/to/config.sqlite',
        'TEST_NAME': 'path/to/test-config.sqlite',
        # ... USER, PASSWORD and PORT left out for brevity
    }
}

在一次测试运行中,我是这样开始的:

python manage.py test myapp.mytest

这会临时创建一个数据库文件 path/to/test-config.sqlite,我需要在另一个应用程序中使用这个文件,并且加载所需的数据。

不过,这个数据库文件是空的,我在一次测试暂停时确认了这一点:

sqlite> select * from someapp_somemodel;

... no results here :(

其他不需要 sqlite 文件的测试用例,使用内存数据库就足够了,没有出现错误。

我有几个问题:

  • 为什么 Django 如果已经创建了数据库文件,却不把数据写入其中?
  • 我该如何让 Django 把数据写入这个临时数据库文件,因为我需要这些数据在临时数据库中?

编辑

我使用的是 Django 1.3.1,如果这有帮助的话。

编辑2

我对数据填充(fixtures)很熟悉,并且用它们来填充数据库,但我的问题是,在测试过程中,数据并没有写入数据库文件。抱歉之前没有说清楚这一点。

编辑3

为了更清楚地说明我的问题,请看以下测试设置(这和我实际做的很接近):

class SomeTestCase(django.test.TestCase):
    fixtures = ["some_fixture.json", "some_other_fixture.json"]

    def testSomething(self):
        import pdb; pdb.set_trace()

testSomething 方法运行到断点时,我启动 sqlite3 程序,并连接到 Django 创建的临时数据库文件。数据填充被加载(我知道,因为其他测试也能正常工作),但数据并没有写入临时数据库文件。

5 个回答

1

来自Django文档的内容:

...当使用SQLite数据库时,测试默认会使用一个在内存中的数据库(也就是说,数据库会在内存中创建,完全不使用文件系统!)。如果你想使用不同的数据库名称,可以在DATABASES中的字典里指定TEST_NAME

此外,如果你了解一下数据加载

...在每个测试用例开始时,在运行setUp()之前,Django会清空数据库,把数据库恢复到调用syncdb后刚开始的状态...

如果你需要一个全新的数据库并加载一些数据,你当然可以通过运行syncdb来创建一个空数据库,然后使用django-admin.py loaddata来加载一些数据!

2

这可能和Django测试如何使用事务有关。

你可以试试在settings.py里关闭所有事务,看看问题是否还存在:

DISABLE_TRANSACTION_MANAGEMENT = True
1

我找到了一种方法,但因为我也玩过hdparm(用过-F或-W 0/1),所以不确定这对你是否有效。我确实重启过并重新尝试过,以确保结果可靠。另外,这个测试没有使用SpatiaLite,不过正如你所说,这可能没什么关系。

总之,我们需要两个屏幕来复现这个问题,screen0用来运行测试,而screen1是一个sh命令行,可以在screen0的进程暂停时使用。

开始测试(screen0):

>>> ./manage.py test testapp
Creating test database for alias 'default'...
Destroying old test database 'default'...
Type 'yes' if you would like to try deleting the test database 'db_test.sqlite', or 'no' to cancel: yes
--Return--
None
> /home/jpic/testproject/testapp/tests.py(16)testSomething()
     14 
     15     def testSomething(self):
---> 16         import ipdb; ipdb.set_trace()

检查创建的测试数据库文件的大小(screen1):

<<< 18:00.39 Mon Feb 20 2012!~/testproject 
<<< jpic@germaine!10004 env
>>> ls -l db_test.sqlite
-rw-r--r-- 1 jpic jpic 49152 2012-02-20 18:00 db_test.sqlite

从python中运行PRAGMA SYNCHRONOUS的sql命令(screen0):

ipdb> from django.db import connection; cursor = connection.cursor()
ipdb> cursor.execute("PRAGMA SYNCHRONOUS")
<django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x294f348>
ipdb> 

检查数据库文件的大小是否增加(screen1):

<<< 18:00.42 Mon Feb 20 2012!~/testproject 
<<< jpic@germaine!10005 env
>>> ls -l db_test.sqlite
-rw-r--r-- 1 jpic jpic 272384 2012-02-20 18:00 db_test.sqlite

数据已经写入文件。

这对我来说有点不太合理,因为显然单独使用PRAGMA SYNCHRONOUS 应该只是查询这个值(在我的情况下是:2/FULL)。但实际上,它却写入了磁盘。请注意,如果你没有2(FULL),那么你应该设置为2:PRAGMA SYNCHRONOUS 2

现在,我不能确定写了什么(是否完全写入了?),因为我无法访问测试数据库:如果我在screen1中运行sqlite db_test.sqlite来连接测试数据库,我无法运行任何命令(既不能选择,也不能.dump),因为出现了“SQL错误:数据库被锁定”。不过,我想这现在是你的问题了B)

撰写回答