在迁移文件中使用特定模型时 Django 测试失败

Django tests fails when using a specific model in a migration file

我已经为特定的 Django 1.11 应用程序手动创建了一个数据迁移文件:

from __future__ import unicode_literals
from django.db import migrations, models

def set_item_things(apps, schema_editor):
    MyModel = apps.get_model('my_app', 'MyModel')
    # NOTE: if I remove this line then the tests will work
    MyOtherModel = apps.get_model('my_other_app', 'MyOtherModel')

    for item in MyModel.objects.all():
        # NOTE: if I remove this line then the tests will work
        thingy = MyOtherModel.get(example_field=item.color) 
        item.other_thing = thingy
        item.save()

class Migration(migrations.Migration):
    dependencies = [
        ('contracts', '0014_my_previous_migration'),
    ]

    operations = [
        migrations.RunPython(set_item_things),
    ]

当我 运行 python manage.py migrate 一切正常时。
但是每当我 运行 我使用 pytest 进行测试时,我都会得到这个:

test setup failed
self = <django.db.migrations.state.StateApps object at 0x10714b2b0>
app_label = 'my_other_app'

    def get_app_config(self, app_label):
        """
            Imports applications and returns an app config for the given label.

            Raises LookupError if no application exists with this label.
            """
        self.check_apps_ready()
        try:
>           return self.app_configs[app_label]
E           KeyError: 'my_other_app'

所以看起来应用程序配置没有正确配置,这已经很奇怪了,因为迁移命令 运行 很顺利。

无论如何:这是my_other_app/apps.py的内容:

from django.apps import AppConfig

class MyOtherAppConfig(AppConfig):
    name = 'my_other_app'

基本上与其他应用程序目录中的所有其他 apps.py 非常相似,当然除了名称。

所以我认为配置应该是正确的,但出于某种原因我的测试不会 运行。

唯一的解决方法是从迁移文件中删除对 my_other_app 的任何引用。

我已经尝试将此添加到 my_other_apps/__init__.py:

default_app_config = 'my_other_apps.apps.MyOtherAppConfig'

但没有任何变化。

我已经尝试查看内部是否存在循环依赖关系 my_other_apps/models.py 但似乎并非如此。

我在这里错过了什么?

我从类似的 中找到了解决方案:MyOtherModel 来自不同的应用程序,因此在我的迁移文件中我必须将上次迁移的应用程序指定为附加依赖项,即:

class Migration(migrations.Migration):
    dependencies = [
        ('contracts', '0014_my_previous_migration'),
        # THIS extra line solves the problem!
        ('my_other_app', '002_my_last_migration'),
    ]

    operations = [
        migrations.RunPython(set_item_things),
    ]

您不应在迁移文件中接触其他应用程序的模型,除非您为该其他应用程序的迁移指定了适当的依赖项。基本上,如果您想使用 my_other_app 中的 MyOtherModel,您必须在迁移中添加条目 dependencies 以指向存在 MyOtherModelmy_other_app 中的迁移并且它处于所需状态。

"Exists" 和 "desired state" 在这里需要一些解释:当 Django 处理迁移时,它不会检查当前在应用程序 models.py 中的实际模型状态,但是尝试从创建迁移的时间点重现您的模型。所以如果你想使用MyOtherModel中的some_field,但是那个字段是在后来的迁移中添加的,你必须至少指向引入这个字段的那个迁移。

以同样的方式,如果您的字段后来被删除,则依赖项必须指向该迁移之前的迁移之一。

请参阅 Django 文档中的 Migrating data between third-party apps

感谢这个 link from this 我在尝试 运行 Django 测试时解决了我的问题:

错误

LookupError: App 'old_app' doesn't have a 'OldModel' model.

解决方案

def forwards(apps, schema_editor):
    try:
        OldModel = apps.get_model('old_app', 'OldModel')
    except LookupError:
        # The old app isn't installed.
        return