Django 数据迁移与 models.py 不匹配

Django data migration mismatch with models.py

我们在项目中使用 django 1.8 和迁移,我们 运行 反复遇到以下问题:

  1. 我们 change/add 迁移模型 1
  2. 我们add/change一些数据来满足迁移 2 的新逻辑
  3. 我们再次更改模型并创建迁移 3

现在,其中一位开发人员同步了 3 个新迁移,但由于 models.py 与数据库之间的不匹配而遇到错误。

到目前为止,我们要么伪造了出错的迁移,要么临时更改了依赖项。但是,这既不系统也不方便。

有没有更好的方法来解决这个问题?

下面是一个简单的例子来说明问题是如何产生的: 原创 models.py

class Test(models.Model):
    a = models.CharField(max_length=200, verbose_name="A")
    b = models.CharField(max_length=200, verbose_name="B")

模型更改前的迁移:

0001_initial.py

class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Test',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('a', models.CharField(max_length=200, verbose_name=b'A')),
                ('b', models.CharField(max_length=200, verbose_name=b'B')),
            ],
        ),
    ]

0002_auto_20160308_1103.py

def testData(apps, schema_editor):
    Test.objects.create(a="aaaa", b="bbb")
class Migration(migrations.Migration):

    dependencies = [
        ('Test', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(testData)
    ]

新models.py

class Test(models.Model):
    a = models.CharField(max_length=200, verbose_name="A")
    b = models.CharField(max_length=200, verbose_name="B")
    c = models.CharField(max_length=200, verbose_name="C", default="c")

上次迁移:

0003_test_c.py

class Migration(migrations.Migration):

    dependencies = [
        ('Test', '0002_auto_20160308_1103'),
    ]

    operations = [
        migrations.AddField(
            model_name='test',
            name='c',
            field=models.CharField(default=b'c', max_length=200, verbose_name=b'C'),
        ),
    ]

运行ning migrate 导致 django.db.utils.OperationalError: table Test_test has no column named c 而 运行ning 第二次迁移。

您没有使用迁移系统提供的功能。特别是,您直接引用了测试模型;但是迁移系统包含 "historical models" 的概念,它是从迁移到那个点动态构建的,因此精确地解决了这个问题。

documentation 进一步解释了这一点,但基本上不是在迁移 0002 中导入测试,而是动态获取它:

def testData(apps, schema_editor):
    Test = apps.get_model("myapp", "Test")
    Test.objects.create(a="aaaa", b="bbb")