Data Migrations in Django

Django has two types of migrations, they are schema and data migrations. Most will be familiar with schema migrations as these are the migrations that Django will auto generate for you using the command makemigrations.

Data migrations on the other hand need to be written by hand. Typical use cases for data migrations are:

  • One-off loading of data into the database (either from a file or directly in code)
  • Backfilling data into a new field
  • Moving data from table to a new field or new table

Creating a data migration is fairly simple:

  1. Run manage.py makemigrations <my_app> --empty --name <what_the_migration_does>
  2. Create a forward migration function with the following signature my_forward_function(apps, schema_editor)
  3. Write the migration! Important Rule here, never import your models directly from your models.py, but using the apps parameter as follows: apps.get_model('apps.MyModel')
  4. Write a reverse migration, this will unapply your migration when running the migrate command backwards (eg manage.py migrate <my_app> zero). If you cannot think of an appropriate reverse migration then you can use the noop function which is referenced as migrations.RunPython.noop
  5. Finally add a RunPython operation in the operations list that specfies the forward and reverse migration.

Overall you will have a python file that looks like this. This migration auto creates some Group instances that relates to another model

from django.db import migrations

def forward_migration(apps, schema_editor):
    Group = apps.get_model('auth.Group')
    MyModel = apps.get_model('MyApp.MyModel')
    for model in MyModel.objects.filter(....):
        group = Group.objects.create(name=f'my_model_group_{model.pk}')
        model.recipe_group = group
        model.save()

def reverse_migration(apps, schema_editor):
    Group = apps.get_model('auth.Group')
    Group.objects.filter(name__startswith='my_model_group_').delete()

class Migration(migrations.Migration):

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

    operations = [
        migrations.RunPython(forward_migration, reverse_migration),
    ]

And that's it! The migration code obviously can be more complex, but this is the basics. More advanced options such as app dependencies, order and atomic options can be found in the docs.