How To Write Custom migrations in Django

Migrations are mainly for keeping the data model of your database up-to-date.

Django will never run same migration file more than once on the same database. All this is managed by table named "django_migrations" which gets created when we first apply the migrations. For each migration(file), a new record(row) is inserted into this table.

There are also a few “special” operations of Migration class which can be used to add our custom migrations.

RunSQL

This allows us to execute raw SQL.

Example:

from __future__ import unicode_literals
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ...
        dependencies goes here
    ]

    operations = [
        migrations.RunSQL("INSERT INTO product (title) VALUES ('Product1');"),
    ]

RunPython

This can be used to run custom Python code. Here code should be separate function that accepts two arguments - first is an instance of django.apps.registry.Apps containing historical models that match the operation’s place in the project history, and the second is an instance of SchemaEditor.

Example:

from __future__ import unicode_literals
from django.db import migrations


def create_countires(apps, schema_editor):
    Country = apps.get_model("app_name", "Country")
    Country.objects.bulk_create([
        Country(name="India"),
        Country(name="USA"),
    ])


class Migration(migrations.Migration):

    dependencies = [
        ...
        dependencies goes here
    ]

    operations = [
        migrations.RunPython(create_countires),
    ]

Once we have the function we can call it from our RunPython operation and then this function will be executed when we run ./manage.py migrate from the command line.

This can be also be used in case if you want to copy few columns data from one table to another table before removing those columns from first table.

After creating a new table, add this custom migration file to copy existing data to new table.

from __future__ import unicode_literals
from django.db import migrations, models


def create_objects(apps, schema_editor):
    Table1 = apps.get_model("test_app", "Table1")
    Table2 = apps.get_model("test_app", "Table2")
    table2_objects = []
    for obj_table1 in Table1.objects.all():
        table2_objects.append(
            Table2(column1=obj_table1.column1, column2=obj_table1.column5)
        )
    Table2.objects.bulk_create(table2_objects)


class Migration(migrations.Migration):

    dependencies = [
        ...
        dependencies goes here
    ]

    operations = [
        migrations.RunPython(create_objects),
    ]

After creating this migration, you can now remove unused columns from table1 and run makemigrations.

Note: While adding this custom migrations, you must load the model using apps.get_model() method as you run migrations, your model can change. For example, a field can be added or removed in a subsequent migration.

    By Posted On
SENIOR DEVELOPER at MICROPYRAMID

Need any Help in your Project?Let's Talk

Latest Comments
Related Articles
Django webpacker - A compression tool to bundles css, js files Nikhila Mergu

django-webpacker is a django compressor tool which bundles css, js files to a single css, js file with webpack and updates your html files with ...

Continue Reading...
Dynamic Models in Django-Part1 (adding new fields to models from admin) Siva Chittamuru

Some times in the production level there may be a chance of adding new fields to our model.With the normal django models when we add ...

Continue Reading...
Preserve file names with sorl for better SEO Ashwin Kumar

We use sorl-thumbnail for scaling images by keeping the original one intact. Sorl proven to be great tool for generating different sized images throughout website. ...

Continue Reading...
open source packages

Subscribe To our news letter

Subscribe and Stay Updated about our Webinars, news and articles on Django, Python, Machine Learning, Amazon Web Services, DevOps, Salesforce, ReactJS, AngularJS, React Native.
* We don't provide your email contact details to any third parties