Skip to main content
 首页 » 编程设计

python之Django SQLite 在测试时试图覆盖数据库

2025年05月04日35dudu

我在 Django 的测试套件中遇到了一个奇怪的问题,我被卡住了,所以我正在寻找一些关于如何修复它或至少在哪里查看的见解。

当我运行以下命令来测试我的泰迪熊应用程序时:

python manage.py test teddybears 

我收到这个错误:

...django/db/backends/sqlite3/base.py", line 344, in execute 
return Database.Cursor.execute(self, query, params) 
django.db.utils.DatabaseError: table "teddybears_teddybear" already exists 

默认情况下,数据库不应该以“test”一词为前缀以避免名称冲突吗?我将数据库重命名为“:memory:”以试图避免这种情况但仍然是同样的错误。

开发工作正常,一切都按预期运行,我只是无法让测试套件工作。任何关于可能导致此问题的原因或在哪里查看的见解都将不胜感激。

我在本地开发工作中使用 SQLite 并使用 Django 1.4.3

这是完整的堆栈跟踪:

> python manage.py test teadybears 
Creating test database for alias 'default'... 
Traceback (most recent call last): 
  File "manage.py", line 10, in <module> 
    execute_from_command_line(sys.argv) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line 
    utility.execute() 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute 
    self.fetch_command(subcommand).run_from_argv(self.argv) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 49, in run_from_argv 
    super(Command, self).run_from_argv(argv) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv 
    self.execute(*args, **options.__dict__) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute 
    output = self.handle(*args, **options) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 72, in handle 
    failures = test_runner.run_tests(test_labels) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 381, in run_tests 
    old_config = self.setup_databases() 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 317, in setup_databases 
    self.verbosity, autoclobber=not self.interactive) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/creation.py", line 271, in create_test_db 
    load_initial_data=False) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 150, in call_command 
    return klass.execute(*args, **defaults) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute 
    output = self.handle(*args, **options) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle 
    return self.handle_noargs(**options) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 102, in handle_noargs 
    cursor.execute(statement) 
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 344, in execute 
    return Database.Cursor.execute(self, query, params) 
django.db.utils.DatabaseError: table "teadybears_teadybear" already exists 

回复:

这是我的数据库设置:

DATABASES = { 
    'default': { 
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 
        'NAME': 'database.sqlite',                      # Or path to database file if using sqlite3. 
        'USER': '',                      # Not used with sqlite3. 
        'PASSWORD': '',                  # Not used with sqlite3. 
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3. 
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3. 
    } 
} 

我确实有这个,但没什么区别:

if 'test' in sys.argv: 
    DATABASES['default']['NAME'] = ':memory:' 

2 X Grrr....

不幸的是,这并没有解决这个问题。除了更改数据库名称之外,我已经尝试了所有建议,但也没有解决它。

我做了所有的建议,包括:

DATABASES = { 
    'default': { 
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 
        'NAME': 'database.sqlite',                      # Or path to database file if using sqlite3. 
        'USER': '',                      # Not used with sqlite3. 
        'PASSWORD': '',                  # Not used with sqlite3. 
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3. 
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3. 
        'TEST_NAME': 'mud', 
    } 
} 

它现在问我:

python manage.py test teddybears 
Creating test database for alias 'default'... 
Destroying old test database 'default'... 
Type 'yes' if you would like to try deleting the test database 'mud', or 'no' to cancel: 

仍然产生相同的错误。

不想将它移动到另一个干净的项目来解决这个问题,但它仍然很烦人。


我已经弄清楚是什么让我绊倒了。该项目的一个模型在导致测试中断的元类上设置了一个值。

class TeddybearExtra(Teddybear): 
 
    class Meta: 
        db_table = 'teddybears_teddybear' 

如您所见,它是原始模型的子类,并且由于明确设置了“db_table”属性,它覆盖了自动生成的表名。这里学到的教训是,在 Meta 对象上设置 db_table 属性会导致测试工具出现不良情况。仅当您绝对需要以这种方式处理时才这样做。

请您参考如下方法:

文档中有两个部分可能与您遇到的问题有关:

https://docs.djangoproject.com/en/dev/topics/testing/overview/#the-test-database

By default the test databases get their names by prepending test_ to the value of the NAME settings for the databases defined in DATABASES. When using the SQLite database engine the tests will by default use an in-memory database (i.e., the database will be created in memory, bypassing the filesystem entirely!). If you want to use a different database name, specify TEST_NAME in the dictionary for any given database in DATABASES.

和..

If your tests rely on database access such as creating or querying models, be sure to create your test classes as subclasses of django.test.TestCase rather than unittest.TestCase.

In the example above, we instantiate some models but do not save them to the database. Using unittest.TestCase avoids the cost of running each test in a transaction and flushing the database, but for most applications the scope of tests you will be able to write this way will be fairly limited, so it’s easiest to use django.test.TestCase.

所以首先,确保您的测试是从 django.test.TestCase 继承而来的。其次,尝试将 TEST_NAME 设置为 testdb.sqlite 并查看是否可以解决您的问题。您可能还想在 /Work/database.sqlite 中指定数据库路径,否则(我认为)数据库将在您执行 管理的目录中创建。 py 来自,这可能并不总是你想要的。

最后,确保您为测试加载了正确的设置文件。