Django迁移文件在另一个应用程序?

时间:2015-04-11 08:31:50

标签: python django django-models django-admin

让我们想象一下以下简化的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:检测到冲突的迁移(在myapp中为0001_initial,0004_auto_20150410_2001)。 要修复它们,请运行&#39; python manage.py makemigrations --merge&#39;

错误消息我无法理解并建议makemigrations --merge因预期而失败:

ValueError:无法找到集合的共同祖先([u&#39; 0001_initial&#39;,u&#39; 0004_auto_20150410_2001&#39;])

我试图覆盖migrations.Migration.__init__来改变派生的app_label,但似乎迁移加载程序忽略了它。

如何调整迁移文件以便它可以在其他应用程序中运行? 原因在于生产externalapp来源无法直接触及,只读。

2 个答案:

答案 0 :(得分:11)

要在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]),)

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

如果可能的话,渴望听到更好/更简单的解决方案。

答案 1 :(得分:1)

自从Django 1.9以来,你可以使用MIGRATION_MODULES设置来提取&#34;外来&#34;模型进入你的应用程序。

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

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

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