markusholtermann
DevelopmentMarkus Holtermann

Django Migrations Recipe #1

This is the first migration recipe I publish for Django’s migration framework. I published it as part of my talk at DjangoCon Europe 2016 in Budapest. This recipe will show that migration code is just Python and Django’s built-in “makemigrations” command might not output the most efficient migration.

This recipe show how one can optimize a migration Django creates.

Take the following 2 models, a “Book” and a “Library”. Each book is associated with exactly one library:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    library = models.ForeignKey('Library')

class Library(models.Model):
    name = models.CharField(max_length=200)

When you run makemigrations for an app with these models you get 3 operations.

$ python manage.py makemigrations
Migrations for 'optimize_makemigrations':
  0001_initial.py:
    - Create model Book
    - Create model Library
    - Add field library to book

You may ask now why the ForeignKey is added as a separate operation. There are 2, maybe 3 reasons behind that:

from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = []
    operations = [
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(...)),
                ('title', models.CharField(max_length=200)),
            ],
        ),
        migrations.CreateModel(
            name='Library',
            fields=[
                ('id', models.AutoField(...)),
                ('name', models.CharField(max_length=200)),
            ],
        ),
        migrations.AddField(
            model_name='book',
            name='library',
            field=models.ForeignKey(to='app.Library'),
        ),
    ]

Now, that we have this example, how can it be optimized? I guess some of you already have an idea:

from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = []
    operations = [
        migrations.CreateModel(
            name='Library',
            fields=[
                ('id', models.AutoField(...)),
                ('name', models.CharField(max_length=200)),
            ],
        ),
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(...)),
                ('title', models.CharField(max_length=200)),
                ('library', models.ForeignKey(to='app.Library')),
            ],
        ),
    ]

The answer to that is, to re-order the CreateModel operations and merge the AddField into the CreateModel for the Book.

Resources