其他应用程序中的 Django 迁移文件?

Django migration file in an other app?

让我们想象一个以下简化的 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),
        ),
    ]

如果上面的迁移schema默认放在<root>/lib/python2.7/site-packages/externalapp/shop/migrations/路径下,manage.py migrate成功,正确添加table字段

但是,如果我将上述迁移文件移动到 myapp/migrations/,则 manage.py migrate 之后会失败并显示

django.core.management.base.CommandError:检测到迁移冲突(0001_initial,0004_auto_20150410_2001 in myapp)。 修复它们 运行 'python manage.py makemigrations --merge'

错误消息我不太理解并建议 makemigrations --merge 失败,预期:

ValueError: 找不到集合的共同祖先([u'0001_initial', u'0004_auto_20150410_2001'])

我试图覆盖 migrations.Migration.__init__ 以改变派生 app_label 但迁移加载器似乎忽略了它。

如何调整迁移文件使其可以在其他应用程序中运行? 原因是在生产中 externalapp 源不能直接接触,是只读的。

要围绕 Django 项目移动迁移文件,就像注入其他应用程序的模型一样,您需要确保在您的 django.db.migrations.Migration 后代中:

  • 显式设置应用程序名称,因为迁移加载程序由迁移文件所在的应用程序自动派生它,否则将尝试在不同模型上执行操作
  • 通知迁移记录器它为其他应用程序提供迁移,否则它仍会将迁移视为未应用(有关已应用迁移的记录存储在 table,当前名为 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]),)

它确实对我有用,并且发现它足够通用。

如果可能,很想知道 better/simpler 解决方案。

从 Django 1.9 开始,您可以使用 MIGRATION_MODULES 设置将 "foreign" 模型迁移到您的应用程序中。

FeinCMS docs 中所述,您在您的应用程序中创建一个新程序包(带有 __init__.py 的文件夹)并在设置中列出外国应用程序,如下所示:

MIGRATION_MODULES = {
    'one': 'yourapp.foreigners.one',
    'other': 'yourapp.foreigners.other',
}

之后你可以manage.py makemigrations one other等等