Beautiful South

I have recently been looking into Django and Python as a new direction for my own programming. Whilst the default database migration is quite cool I think that for longer term projects with lots of iterative changes dbSync just does not cut it.

It didn’t take much digging to find mention of a project called South which is a more fully featured database migration tool for grown ups. Having had the migrations work without issue in DBSync I thought that once I had got South installed it would be a simple case of migrating and the job would be, as they say, ‘a good one’. Turns out that South is maybe a little less forgiving than I had thought….

I started off with some of my models defined…. Creating the actual upgrade scripts is as simple as issuing the following command:

$ python manage.py schemamigration MyApplication --initial

A cursory examination of my app and I now see a migrations folder, contained within is a 0001_initial.py file which contains the code required to upgrade my database. Great, without examining too closely I continued to apply the patches to the database

$ python manage.py migrate MyApplication

This too went of without issue and a cursory test of one of the models proved that my changes had indeed been applied:-

>>> from MyApplication.models import MetricIndex
 >>> MetricIndex.objects.all() []

Doesn’t look like much, but the empty block of course means that I have returned an empty array and NOT a big fat juicy error which is good! However my cursory examination of the upgrade script meant that I missed the detail…. I am using abstract inheritance for my tables because with many of the tables they have a lot of common fields. These fields are defined within an abstract model interface and then each table inherits from that. The upshot is I should have 1 database table created for each concrete class and no tablesĀ  created for the abstract classes. This was not what the scripts had generated within them. My model classes were defined thus:-

class ModelBase():
 Name =models.CharField(max_length=255)
 Order =models.IntegerField(default=-1)
 class meta:
 abstract =True
class MetricIndex(ModelBase):
 pass

Strange it should have worked… I should have had one MetricIndex table with two fields and no ModelBase table. The answer turned out to be frustratingly simple ( and remember, this worked correctly with dbSync). My abstract class was not defined correctly, ‘class meta’ should in fact have been ‘class Meta’. I applied the changes to the code as below

class ModelBase():
 Name =models.CharField(max_length=255)
 Order =models.IntegerField(default=-1)
 class Meta:
 abstract =True
class MetricIndex(ModelBase):
 pass

I then prepared the database script to migrate to the next iteration of the schema thus…

$ python manage.py schemamigration MyApplication --auto

And applied the schema changes as below

$ python manage.py migrate MyApplication

Voila…. I now had one properly formed MetricIndex table and no ModelBase table. Onward and upward and I urge you to use this great tool!