从 1.8 升级到 2.2.4 后,Django 无法为单元测试创​​建表

Django unable to create tables for unit testing after upgrade from 1.8 to 2.2.4

从 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

沿线的某个地方,测试用例使用的数据库需要附加到它们。在实例化测试数据库之前,Django 会根据对象列出所有需要的数据库。在此之后,它会为它们制作模式。

如果您添加到基础 class 中,您将继承所有测试,或者添加到每个 class 您从 Django class 继承的 classes a像这样的行:

databases = settings.DATABASES

您会发现您的数据库应该实例化。

这个版本的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 的 class,并像这样配置数据库:

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()