Using South to change a Django model’s parent class

I recently wanted to introduce a new parent model for some of my Django models. (The model is called “PayableModel” and is used for any model for which you might pay money.)

Like any reasonable person, I use South to manage my models. This is a Good Thing.

However, much like changing AUTH_USER_MODEL, there is not much support for how to go through this processĀ and keep your existing data. So, in the hopes it’s useful, here’s what I did.

Note: this is a one-way migration. Your model’s ‘id’ field is going to be dropped, and it’s pretty hard to get that back (although now I have some ideas). In any case…

  1. Create your new parent model and run schemamigration as normal (python manage.py schemamigration your_app_name –auto)
  2. In the to-be child model(s), create a new nullable IntegerField called parentmodel_ptr. For example:
    paymentmodel_ptr = models.IntegerField(null=True)
  3. Run schemamigration again. If you’re into that sort of thing, add a “depends_on” clause to the migration to make it dependent on the migration from step #1.
  4. Create a datamigration. (Fancy!):
    python manage.py datamigration your_app_name \
      populate_me_pointers
  5. Edit the datamigration:
    def forwards(self, orm):
      for child in orm.ChildModel.objects.all():
        # in which we create the parent:
        parent = orm['parent.ParentModel']()
        parent.save()
        child.parentmodel_ptr = parent.pk
        child.save()

    This snazzily creates the parents and links it to the secret Django magic _ptr field that will tell Django where to find the parent. At this point, the field is nothing special.

  6. Edit your model to (1) remove the parentmodel_ptrĀ and at the same time add the new parent class. Then run another schemamigration.

The brilliance of this model is I have idea how South converts the IntegerField to the foreign key. It will see the field as changing, rather than being deleted and re-added, because you made the change all at once.

I hope this helps!

If there was one post that made me want to switch to a Markdown-based blog…