Using South for schema and data migrations in Django

South is a schema and data migrations for Django. In an easy way you may update your database tables after you change your models. It also keeps all migrations in the codebase allowing to migrate backward if needed. In this article I'll show some standard South usage cases.

pip install South

python manage.py schemamigration APPLICATION_NAME --initial

python manage.py migrate APPLICATION_NAME

from django.db import models class MyModel ( models . Model ): name = models . CharField ( max_length = 100 )

class MyModel ( models . Model ): name = models . CharField ( max_length = 100 ) description = models . TextField ( blank = True )

python manage.py schemamigration APPLICATION_NAME --auto

In this example south will do everything on its own and we can just execute the migration.

Now lets try a field that can't be empty:

class MyModel ( models . Model ): name = models . CharField ( max_length = 100 ) description = models . TextField ( blank = True ) number = models . IntegerField ()

? The field 'MyModel.number' does not have a default specified, yet is NOT NULL. ? Since you are adding this field, you MUST specify a default ? value to use for existing rows. Would you like to: ? 1. Quit now, and add a default to the field in models.py ? 2. Specify a one-off value to use for existing columns now

You can choose 1 and quit (and then for example add default to the field) or use 2 and provide a default value for the migration (value used only for entries existing at the time of migration).

slug = models . SlugField ( unique = True )

slug = models . SlugField ( unique = True , null = True )

The plan is simple - we create such column (migration), then we do a data migration (we make unique values for the existing entries) and in the end we remove the null with another schema migration.

python manage.py datamigration APPLICATION_NAME MIGRATION_NAME

# -*- coding: utf-8 -*- import datetime from south.db import db from south.v2 import DataMigration from django.db import models class Migration ( DataMigration ): def forwards ( self , orm ): # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." def backwards ( self , orm ): "Write your backwards methods here."

The forwards method is used to make the migration. backwards is used to do a backward migration (if it's something complex/non reversible you can disable it). The key element is to write the migration.

def forwards ( self , orm ): # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." for i in orm [ 'first_app.MyModel' ] . objects . all (): i . slug = i . id i . save ()

python manage.py migrate APPLICATION_NAME NUMER

python manage.py migrate first_app 0005

python manage.py migrate APPLICATION_NAME zero

In some cases when you have migrations covering model/database relations there may be a problem with the order in which migrations are executed. The migration with the relation may try to execute before the related table will be created by another migration. To apply correct order we can use "depends_on" in the migration class:

depends_on = ( ( "APPLICATION_NAME" , "NAZWA_MIGRACJI" ), )

Such problems may show up during tests or build processes where everything is created from scratch.

RkBlog