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 schemamigration your_app_name auto)
  2. In the to-be child model(s), create a new nullable IntegerField called parentmodel_ptr. For example: <pre>paymentmodel_ptr = models.IntegerField(null=True)</pre>

  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!): <pre>python datamigration your_app_name

  5. Edit the datamigration: <pre>def forwards(self, orm): for child in orm.ChildModel.objects.all(): # in which we create the parent: parent = orm‘parent.ParentModel’ child.parentmodel_ptr =</pre>
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.</li> 

  * Edit your model to (1) remove the parentmodel_ptr _and at the same time_ add the new parent class. Then run another schemamigration.</ol> 

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..._