Last modified 6 years ago Last modified on 10/03/09 22:08:21

Tutorial, Part 1: The Basics

Welcome to South. This tutorial is designed to give you a runthrough of all the major features; smaller projects may only use the first lot of features you learn, but everything is built in for a reason!

If you've never heard of the idea of a migrations library, then please read WhatAreMigrations first; that will help you get a better understanding of what both South and others such as django-evolution are trying to achieve.

This tutorial assumes you have South installed correctly; if not, see Download for instructions.

Apps and Migrations

The first principle to learn is that, in South, individual apps are either 'migrated' or not - for example, the django.contrib.admin app isn't migrated - it has no migrations, whereas the app you'll create along with this tutorial will have migrations, and so is 'migrated'.

The reason this is important is that, with South enabled, you will have two ways of changing the database schema:

  • ./ syncdb - As before, this only creates models' tables directly, but with South enabled it will only do this for non-migrated apps.
  • ./ migrate - This command will change the database schema for migrated apps only.

South differentiates between migrated and non-migrated apps by seeing if they have a appname/migrations/ directory. To create this directory, and create migrations, there is one more important command:

  • ./ startmigration - Creates migrations for apps, either blank ones, ones with user-specified actions, or ones with automatically-detected changes - we will cover all three of these uses.

Kicking Off

First, create an application the usual way: startproject southtut
cd southtut
<< add south to INSTALLED_APPS >>
./ syncdb

Second, you will need an app, with a few models. It doesn't matter what; if you want to follow the examples, make a new app called 'southdemo': startapp southdemo

Give it the following file:

from django.db import models

class Lizard(models.Model):
    age = models.IntegerField()
    name = models.CharField(max_length=30)

class Adopter(models.Model):
    lizard = models.ForeignKey(Lizard)
    name = models.CharField(max_length=50)

Don't forget to update to:

  • pick a DATABASE_ENGINE, and set the relevant settings;
  • add both 'south' and 'southdemo' to the list of INSTALLED_APPS.

(Note that you shouldn't pick sqlite3 for this tutorial, since the sqlite3 python bindings do not currently support changing existing columns. See #52)

Now, we need to make our first migration. The way South works is that, on a new installation, it will run through the entire history of migrations for each app, rather than just using syncdb. This helps keep things consistent, and lets you write migrations that put in complex initial data, but it does mean that doing all migrations for an app, one after the other, should take a database from blank to the most recent schema.

Specifically, this means that ./ migrate replaces ./ syncdb for applications with migrations; the effect of syncdb is recreated by the migrations. You should not run syncdb on an application before you migrate it, if it is a new app (if you are converting an existing app, see ConvertingAnApp).

For this reason, the first migration has to be one that creates all the models you currently have. startmigration accepts a --model parameter, which tells it to make a migration that creates the named model, so we could do this:

./ startmigration southdemo initial --model Lizard --model Adopter

(The arguments to startmigration are, in order, app name, migration name, and then parameters)

However, there is a shortcut for adding all models currently in the file, which is --initial:

./ startmigration southdemo --initial

(You can also pass in a migration name here, but it will default to 'initial')

Running this, we get:

$ ./ startmigration southdemo --initial
Creating migrations directory at '/home/andrew/Programs/mornsq/southdemo/migrations'...
Creating in '/home/andrew/Programs/mornsq/southdemo/migrations'...
 + Added model 'southdemo.Lizard'
 + Added model 'southdemo.Adopter'

As you can see, it has made our southdemo/migrations directory for us, as well as putting an file in it (to mark it as a Python package - this is also required).

If you open up the migration file it made - southdemo/migrations/ - you'll see this:

from south.db import db
from django.db import models
from southdemo.models import *

class Migration:
    def forwards(self, orm):
        # Adding model 'Lizard'
        db.create_table('southdemo_lizard', (
            ('age', models.IntegerField()),
            ('id', models.AutoField(primary_key=True)),
            ('name', models.CharField(max_length=30)),
        db.send_create_signal('southdemo', ['Lizard'])
        # Adding model 'Adopter'
        db.create_table('southdemo_adopter', (
            ('lizard', models.ForeignKey(orm.Lizard)),
            ('id', models.AutoField(primary_key=True)),
            ('name', models.CharField(max_length=50)),
        db.send_create_signal('southdemo', ['Adopter'])
    def backwards(self, orm):
        # Deleting model 'Lizard'
        # Deleting model 'Adopter'

    models = {
        'southdemo.lizard': {
            '_stub': True,
            'id': ('models.AutoField', [], {'primary_key': 'True'})

Migrations in South are, as you can see, just Migration classes with forwards() and backwards() methods, which get run as you go forwards or backwards over the migration respectively.

Each method gets an 'orm' parameter, which contains a 'fake ORM' - it will let you access any frozen models for this migration (details on frozen models are covered in part three of the tutorial).

Most of the time, you can get startmigration to write either all or most of a migration for you; continue to part two of the tutorial for more about changing models.