Migrations

Noboy is perfect. Not even developers.

In every project change happens. Old models need to be updated and new ones need to be added. The latter is not much of a problem, as androrm simply recognizes your new models and creates new tables for them. The same does not hold, if you add fields to your existing models. To save time, androrm won't check each time if something has changed on your models and perform the respective updates. In the past that meant you needed to manually drop the table and have it recreated by androrm. We all knew that this is not particularly good. To overcome this issue, we introduce migrations. This page will teach you how to update your model classes with ease.


The Basics

In order to run any migration on one of your models, you need to override the migrate method of the Model class. This method will be called after androrm has initialized all the models and is used to run any kind of migration. The following example shows you, how an empty migrate method would look like.

public class Authro extends Model {

    protected CharField mName;

    public Authro() {
        mName = new CharField();
    }

    @Override
    protected void migrate(Context context) {
        return;
    }

}

The context instance you need to hand to the method will later be used to roll out all migrations.


Adding Fields

In most cases you have defined a model with some fields on it. We did so with the Author model. Currently, only a name can be assigned to an author. But maybe this author also wrote some book using a synonym. So first up, we add this new field to the model itself.

public class Authro extends Model {

    protected CharField mName;
    protected CharField mSynonym;

    public Authro() {
        mName = new CharField();
        mSynonym = new CharField();
    }

    @Override
    protected void migrate(Context context) {
        return;
    }

}

So far, so good. The problem here is that androrm can not detect, that the signature of the table has changed and that a new field should be added. You need to help out a little bit. Using a Migrator instance, we will tell androrm what to do.

public class Authro extends Model {

    protected CharField mName;
    protected CharField mSynonym;

    public Authro() {
        mName = new CharField();
        mSynonym = new CharField();
    }

    @Override
    protected void migrate(Context context) {
        Migrator<Authro> migrator = new Migrator<Authro>(Authro.class);

        // tell the name of the field an the type
        migrator.addField("mSynonym", new CharField());

        // roll out all migrations
        migrator.migrate(context);
    }

}

Using the migrator we can run several migrations on the model. The good thing here is that androrm will keep track of the migrations, you have already rolled out and if they are necessary. So if your code runs on a fresh install were everything is right in place from minute one, no migrations will be run, and if it runs on an old installation the migrations will be applied.

What is important to mention, is that you should not remove migrations. All migrations, that you have applied to get from the first version of your model, to your current one should remain in the migrate method. This will make sure that everybody who is using your app will work on the same data scheme.


Renaming Models

If you renamed one of your model classes you run into one big problem. Even though androrm recognizes the new class it will only create a new, empty table for it. With migrations you can now simply tell androrm that you have renamed one of your tables and it will make sure that all of your previous data is right in place.

public class Author extends Model {

    protected CharField mName;
    protected CharField mSynonym;

    public Author() {
        mName = new CharField();
        mSynonym = new CharField();
    }

    @Override
    protected void migrate(Context context) {
        Migrator<Author> migrator = new Migrator<Author>(Author.class);

        // tell the name of the field and the type
        migrator.addField("mSynonym", new CharField());

        // tell androrm the old name of the model
        migrator.renameModel("Authro", Author.class);

        // roll out all migrations
        migrator.migrate(context);
    }

}

As you might have noticed one small error occurred while I was writing this document :) Unfortunately I misspelled Author. To get rid of that mistake we will now apply a migration to rename the existing table for the model Authro to the correct value Author. To do so, we call renameModel on the migrator instance, tell it the name of the old model, and hand in the class of the new one.

androrm on github

Django is a registered trademark of the Django Foundation. Android is a registered trademark of Google Inc.