Файл миграции 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 и т.п.

Другие вопросы по тегам