Daniele Bernardini
Daniele Bernardini

Reputation: 1536

Django data migration mismatch with models.py

We use django 1.8 and migrations in our project and we run repeatedly into the following problem:

  1. We change/add a model with migration 1
  2. We add/change some data to satisfy new logic with migration 2
  3. We change again the model and create migration 3

Now one of the developers sync the 3 new migrations and encounters an error due to the mismatch between models.py and the database.

So far we have either faked the migrations which errors out or we changed dependencies ad hoc. This is neither systematic nor convenient though.

Is there any better way to approach the problem?

Following is a simple example of how the problem arise: original models.py

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

migrations before model change:

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)
    ]

new 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")

last migration:

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'),
        ),
    ]

running migrate results in django.db.utils.OperationalError: table Test_test has no column named c while running the second migration.

Upvotes: 1

Views: 796

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599926

You are not using the functionality that the migrations system provides. In particular, you're referencing the Test model directly; but the migrations system includes the concept of "historical models" which are built up dynamically from the migrations up to that point, which therefore solves this problem precisely.

The documentation explains this further, but basically instead of importing Test in migration 0002, you should get it dynamically:

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

Upvotes: 3

Related Questions