Тесты Django не выполняются при использовании определенной модели в файле миграции
Я вручную создал файл миграции данных для конкретного приложения 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'
Таким образом, похоже, что конфигурация приложения не настроена должным образом, и это уже странно, потому что команда migrate прошла гладко.
Во всяком случае: это содержание 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
но это не так.
Что мне здесь не хватает?
3 ответа
Я нашел решение из аналогичного вопроса SO: 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),
]
Не следует прикасаться к моделям из других приложений в вашем файле миграции, если вы не укажете правильные зависимости для миграции этого другого приложения. В основном, если вы хотите использовать MyOtherModel
от my_other_app
, вы должны добавить запись в dependencies
в вашей миграции, чтобы указать на миграцию в my_other_app
в котором MyOtherModel
существует и находится в желаемом состоянии.
"Существует" и "желаемое состояние" нуждается в некотором объяснении здесь: когда Django имеет дело с миграциями, он не проверяет фактическое состояние модели, которое в данный момент находится в models.py
вашего приложения, но пытается воспроизвести ваши модели с момента времени, когда была создана миграция. Так что если вы хотите использовать some_field
от MyOtherModel
, но это поле было добавлено в более поздней миграции, вы должны указать хотя бы ту миграцию, в которой это поле было введено.
Таким же образом, если позднее ваше поле было удалено, зависимости должны указывать на одну из миграций до этой миграции.
См. Миграция данных между сторонними приложениями из документации Django.
Благодаря этой ссылке из этого ответа я решил свою проблему при попытке запустить тест 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