Wiki

Clone wiki

Migratory / Tutorial

Tutorial

Let’s learn by example. And let's use, for example, the Django Tutorial 1.

Create Your Project

Following the example, create a new project: django-admin.py startproject mysite

Go into mysite/ and edit your new settings.py to adjust your database settings, and add migratory to your INSTALLED_APPS, for instance:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.migratory',  # Migratory
)

When you're ready, do a python manage.py syncdb to setup the base tables.

Create the polls app: python manage.py startapp polls

Edit polls/models.py to match the django tutorial:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()

And then edit your settings.py again to add the new app:

INSTALLED_APPS = (
    ...
    'django.contrib.migratory',
    'mysite.polls'    
)

And now finally, perform a syncdb: python manage.py syncdb

Create Some Data

Following the Django Tutorial, create a poll in the shell:

python manage.py shell

>>> from mysite.polls.models import Poll, Choice
>>> import datetime

# Create a poll
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())
>>> p.save()

# Add some choices
>>> p.choice_set.create(choice='Not much', votes=0)
>>> p.choice_set.create(choice='The sky', votes=0)

# Add your vote
>>> c = p.choice_set.get(choice='The sky')
>>> c.votes = 1
>>> c.save()

Now, if you want to add the extra __unicode__ and was_published_today() go ahead, it's not really important for this tutorial.

Make Changes

Okay, so this is where it gets interesting.

We created some data, but now we realize that we need to be able to turn on and off seperate polls. We need to add an "enabled" field. Okay, no problem:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    enabled = models.BooleanField(default=True)   # New Field

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()

Now we have to reflect the changes in our database. To do so, we create a migration:

> python manage.py migrate polls add-enabled-on-polls 

Let's break it down:

python manage.py
The usual manage.py start.
migrate
Create a new migration.
polls
The app we want to create the migration for.
add-enabled-on-polls
A slug for our migration used as an identifier.

We then see an overview of what's going on:

Adding '2008-12-30-add-enabled-on-polls.py' to manifest...
Writing migration to: ../mysite/polls/migrations/2008-12-30-add-enabled-on-polls.py
Writing snapshot to: ../mysite/polls/migrations/2008-12-30-add-enabled-on-polls.snap
Changes to the model 'Poll':
    Add the new field 'enabled'.

Please look over the changes. When you feel confident they are correct, issue a 'syncdb':
> python manage.py syncdb

It tells us that it added a new migration script named '2008-12-30-add-enabled-on-polls.py', although the date will be changed for you. Where is the script? Well the app layout will now look like this:

polls/
    __init__.py 
    migrations/
        2008-12-30-add-enabled-on-polls.py
        2008-12-30-add-enabled-on-polls.snap
        __manifest__.py
    models.py
    views.py

You can see it also created the file 2008-12-30-add-enabled-on-polls.snap, which is a snapshot of our current models for reference, and is important in executing the migration later on.

In addition, it tells us that it added the script to the manifest, which is the newly created __manifest__.py in the migrations/ folder. This file lists, in order, each migration script, it looks like:

[
    '2008-12-30-add-enabled-on-polls.py',
]

The output also gives us a description of everything that the migration will do:

Changes to the model 'Poll':
    Add the new field 'enabled'.

Ah, correct! We want to add the new field 'enabled', exactly. Let's look at what the script actually does:

"""
Django Migration 2008-12-30-add-enabled-on-polls.py

"""

def up(database):
    database.add_field('Poll', 'enabled')

Pretty simple, the migration defines an up() function that takes a Database Manager as its one and only argument. The database manager allows you to adjust the database and, in between adjustments, use the models as normal with the Django ORM.

Well, that looks perfectly good to me, so let's execute it:

python setup.py syncdb

And we're done, our database should now represent our models.py quite well.

>>> from mysite.polls.models import Poll, Choice
>>> p = Poll.objects.get()
>>> p.question
u"What's up?"

>>> p.enabled
True

Updated