从 1.8 升级到 2.2.4 后,Django 无法创建用于单元测试的表
Posted
技术标签:
【中文标题】从 1.8 升级到 2.2.4 后,Django 无法创建用于单元测试的表【英文标题】:Django unable to create tables for unit testing after upgrade from 1.8 to 2.2.4 【发布时间】:2020-01-06 10:55:05 【问题描述】:从 Django 1.8 成功升级到 Django 2.2.4 后,当 我运行测试它失败了,因为 Django 没有创建数据库表。
我的 test_settings.py 文件在升级前工作正常。
调试 Django db/backends 后,看起来连接已创建,但表并未创建。 我怀疑 test_setting.py 没有配置好,尽管我从 setting.py 文件中复制了除了数据库配置(仍然是 SQLite)之外的所有内容。
数据库配置:
DATABASES =
'default':
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test_database'
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'my_app',
'mptt',
'corsheaders',
# audit app
'easyaudit',
'kronos',
'django.contrib.admin',
]
我得到的回溯(例如,这里是 auth_user,但它以相同的方式为所有表重现):
Traceback (most recent call last):
File "C:\Users\owner\Desktop\workspace\my_project\MyProject\services\tests\test_logging.py", line 33, in setUpClass
cls.user = User.objects.get_or_create(username='logging_test_user', password='test_password')
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 538, in get_or_create
return self.get(**kwargs), False
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 402, in get
num = len(clone)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 256, in __len__
self._fetch_all()
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 1242, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 55, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\sql\compiler.py", line 1100, in execute_sql
cursor.execute(sql, params)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 67, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 76, in _execute_with_wrappers
return executor(sql, params, many, context)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\sqlite3\base.py", line 383, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: auth_user
使用环境变量执行的测试
DJANGO_SETTINGS_MODULE=MyProject.test_settings
【问题讨论】:
在运行测试时是否看到“Creating test database for alias 'default'...”? 另外,您的开发/生产数据库是什么?为什么不在你的测试中使用相同的东西呢?例如,如果您使用 PostgreSQL 数据库并使用特定的 pg 功能(如JSONField
),您的测试将失败。
我在我的环境中看不到它,但在我的同事中,它已显示,但仍然出现相同的错误。我的开发数据库是 PostgreSQL。我们没有使用 JSONField,所以这不是问题。
【参考方案1】:
这个版本的django好像有bug(可能也是2.2之前的,我没查过)。
databases = self.get_databases(suite)
old_config = self.setup_databases(aliases=databases)
这里的databases变量在任何情况下都不会是None,因为在get_databases函数中它调用_get_databases()并且如果它找不到任何如上所述配置的数据库,数据库将设置为set(),并且在 setup_databases 函数中有一个函数叫做
get_unique_databases_and_mirrors
检查是否没有在测试中配置数据库,如果没有,它将采用设置文件中配置的数据库,但是因为它设置为空集(set())而不是进入这种情况,因此不会创建任何数据库。
要传递该错误,您可以创建一个继承 unittests.Testcase 的类,并像这样配置数据库:
import django
import unittest
from django.conf import settings
class MyTestCase(unittest.TestCase):
databases = settings.DATABASES
@classmethod
def setUpClass(cls) -> None:
super(MyTestCase, cls).setUpClass()
django.setup()
【讨论】:
【参考方案2】:在某个地方,需要将测试用例使用的数据库附加到它们上。在实例化测试数据库之前,Django 根据对象列出所有需要的数据库。在此之后,它会为它们制作架构。
如果你为你的所有测试添加你继承自的基类,或者你从 Django 类子类化的每个类中添加如下一行:
databases = settings.DATABASES
你会发现你的数据库应该实例化。
【讨论】:
谢谢你,迪伦。一点点更正:您需要发送数据库字典本身,而不是发送数据库名称。当设置来自 django.conf 导入设置时,您可以通过发送 settings.DATABASES 来进行通用化以上是关于从 1.8 升级到 2.2.4 后,Django 无法创建用于单元测试的表的主要内容,如果未能解决你的问题,请参考以下文章
升级到 1.8 后进行迁移时出现 DjangoUnicodeDecodeError
从 1.8 升级到 1.9 Django Admin get_urls 不起作用