Django 1.7:测试和 url 从模型构建的模式引发了 "no such table"

Django 1.7: tests and url patterns built from models raises "no such table"

我正在尝试将一个大型 Django 项目迁移到 1.7 版。

我已经解决了所有问题并且网站运行顺利,但我无法再运行 测试套件。

问题出在 Django 的应用注册表中,在 populate 方法中。有一些应用程序的 url 模式在相当早的阶段就使用了 ORM。

例如:

    url(r'^(?:(?P<platform_slug>%s)/)?(?:(?P<genre_slug>%s)/)?(?:(?P<year>%s)/)?$' % (
    r'|'.join([i['slug'] for i in Platform.active_objects.values("slug")]), 
    r'|'.join([i['slug'] for i in Genre.objects.values("slug")]),
    r'|'.join([str(i) for i in YEAR_FILTER_RANGE])),
    views.archive, name="gamecard_archive")

这是一个复杂的模式,允许可选但可区分的参数,但它与问题无关。

当我 运行 测试时,我得到了臭名昭著的 django.db.utils.OperationalError: no such table: contrib_platform 因为,显然,测试 运行 仍然没有在那个阶段创建数据库。执行整体测试设置的顺序与 1.6 明显不同。

虽然一种解决方案是避免在测试期间访问 url 配置中的应用程序模型,方法是将这些规则替换为更简单的版本检查 sys.argv,如

if 'test' in sys.argv:
    [simple url pattern here]
else:
    [uber url pattern here]

我想知道是否有人想出一个更优雅、更便携的解决方案。

更新 我想添加回溯堆栈的头部。
它表明它确实与测试没有严格关系,但与应用程序配置有关。
我真的不能说这是一种回归,因为 Django 1.7 已经存在了一段时间,我怀疑之前没有人发现它。只是我项目的一个角落案例。然而,在 Django 1.6 中,它就像一个魅力,很明显可以在早期阶段访问数据库。

Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "[...]/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
  File "[...]/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute
django.setup()
  File "[...]/lib/python2.7/site-packages/django/__init__.py", line 21, in setup
apps.populate(settings.INSTALLED_APPS)
  File "/Users/germanoguerrini/.virtualenvs/multi17/lib/python2.7/site-packages/django/apps/registry.py", line 115, in populate
app_config.ready()
  File "[...]/lib/python2.7/site-packages/django/contrib/admin/apps.py", line 22, in ready
self.module.autodiscover()
  File "[...]/lib/python2.7/site-packages/django/contrib/admin/__init__.py", line 23, in autodiscover
autodiscover_modules('admin', register_to=site)
  File "[...]/lib/python2.7/site-packages/django/utils/module_loading.py", line 74, in autodiscover_modules
import_module('%s.%s' % (app_config.name, module_to_search))
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
...

一般来说,我不会认为从模型实例构建 URL 是一个好习惯。所以可能会尝试为此找到另一种解决方案,例如。通过做类似 Genre.objects.filter(platform__slug=platform_slug) 的事情(不知道你的确切模型结构)。

您遇到的问题很可能是由于 App-loading refactoring which was introduced with Django 1.7 and changes a lot in the way your models a loadeded etc. So you should try to put the url-changing code in the AppConfig.ready() 方法引起的,该方法是 运行 在 Django 完成加载所有必要内容之后。但尽管如此,我通常会避免像这样基于数据库中的数据构建您的网址。

您的解决方案(url 由数据库指定的配置 table)在一个简单的应用程序中与 Django 1.7 配合得很好。您可能有复杂的依赖关系或循环导入,您的某些模型在导入时需要配置 urls。可以消除相互依赖,例如在真正使用时通过在函数内部导入。您使用 'test' in sys.argv 的解决方案也很好,但更好的是在不排除测试的情况下解决它,以便您可以编写集成测试以及 urls.

的复杂代码

奇怪的是你的测试有问题而不是其他命令(例如python manage.py runserver),因为你的问题很快就出现在设置中,命令之间可能没有任何区别在测试运行器之前。

标准解决方案是在您的 TesCase 中定义属性 urls。例如一行urls = 'myapp.test_urls'。请参阅文档 test urlconf configuration。这在以后可能会有用,在你修复你的错误之后,或者你应该为 urls 配置一个带有测试数据的夹具,这似乎有点过分了。