Файл миграции Django в другом приложении?
Давайте представим следующий упрощенный проект Django:
<root>/lib/python2.7/site-packages/externalapp/shop
<root>/myapp
myapp
также расширяется externalapp.shop.models
модели, добавив несколько полей. manage.py makemigrations
сгенерировал следующий файл миграции схемы с именем 0004_auto_20150410_2001.py:
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
# __init__ is added by me as an attempt how to tell django's
# migration loader operations are for the different application
def __init__(self, name, app_label):
super(Migration, self).__init__(name, 'shop')
dependencies = [
('myapp', '__first__'),
('shop', '0003_auto_20150408_0958'),
]
operations = [
migrations.AddField(
model_name='product',
name='vat',
field=models.ForeignKey(to='myapp.VAT', null=True),
),
]
Если приведенная выше схема миграции находится в <root>/lib/python2.7/site-packages/externalapp/shop/migrations/
путь по умолчанию, manage.py migrate
успешно и поля таблицы добавлены правильно.
Однако если я переместить вышеупомянутый файл миграции в myapp/migrations/
после manage.py migrate
не удается с
django.core.management.base.CommandError: Обнаружены конфликтующие миграции (0001_initial, 0004_auto_20150410_2001 в myapp). Чтобы исправить их, запустите 'python manage.py makemigrations --merge'
сообщение об ошибке я не совсем понимаю и предложил makemigrations --merge
терпит неудачу с ожидаемым:
Ошибка значения: не удалось найти общего предка набора ([u'0001_initial', u'0004_auto_20150410_2001'])
Я пытался переопределить migrations.Migration.__init__
изменить производное app_label
но кажется, загрузчик миграции игнорирует это.
Как настроить файл миграции, чтобы он мог работать из другого приложения? Причина в производстве externalapp
источники не могут быть непосредственно затронуты, только для чтения.
2 ответа
Для перемещения файла миграции по проекту Django, как в случае внедрения моделей из других приложений, необходимо убедиться, что django.db.migrations.Migration
потомок:
- явно задайте имя приложения, так как загрузчик миграций получает его автоматически приложением, в котором находится файл миграции, и в противном случае попытается выполнить операции на разных моделях
- Регистратор уведомлений о миграциях обеспечивает миграцию для другого приложения или по-прежнему рассматривает миграцию как неприменимую (записи о примененных миграциях хранятся в таблице, в настоящее время называемой
django_migrations
)
Я решил проблему в инициализаторе миграции, который может выглядеть так:
from django.db import migrations
TARGET_APP = 'shop' # application label migration is for
class Migration(migrations.Migration):
def __init__(self, name, app_label):
# overriding application operated upon
super(Migration, self).__init__(name, TARGET_APP)
# specify what original migration file it replaces
# or leave migration loader confused about unapplied migration
replaces = ((TARGET_APP, __module__.rsplit('.', 1)[-1]),)
Это действительно работает для меня и найти его достаточно общим способом.
Желая услышать о лучшем / более простом решении, если это возможно.
Начиная с Django 1.9 есть MIGRATION_MODULES
настройка, которую вы можете использовать для переноса миграции "чужих" моделей в ваше приложение.
Как указано в документации FeinCMS, вы создаете новый пакет (папку с __init__.py
) в вашем приложении и перечислите сторонние приложения в настройках следующим образом:
MIGRATION_MODULES = {
'one': 'yourapp.foreigners.one',
'other': 'yourapp.foreigners.other',
}
После этого вы можете просто manage.py makemigrations one other
и т.п.