Skip to content

Instantly share code, notes, and snippets.

Last active March 24, 2017 22:29
Show Gist options
  • Save smcoll/5dc21fd7c35e06f0c34180ce295ca8ce to your computer and use it in GitHub Desktop.
Save smcoll/5dc21fd7c35e06f0c34180ce295ca8ce to your computer and use it in GitHub Desktop.
Django migration for converting model to django-polymorphic child model
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.db.models import F
def seed_baseitem(apps, schema_editor):
""" For each Foo, create a BaseItem with the same primary key value and
the appropriate `polymorphic_ctype` value. This will be used by a new
`Foo.baseitem_ptr` foreign key so that each `Foo` instance can retain
its ID after `Foo` is converted to a polymorphic child class
Foo = apps.get_model('myapp', 'Foo')
BaseItem = apps.get_model('myapp', 'BaseItem')
ContentType = apps.get_model('contenttypes', 'ContentType')
ct = ContentType.objects.get_for_model(Foo)
# if any other fields need data migrated to BaseItem, do that here
) for obj in Foo.objects.only('id')
def populate_foo_baseitem_ptr(apps, schema_editor):
""" Populate the `baseitem_ptr` column with the corresponding `id` value
Foo = apps.get_model('myapp', 'Foo')
class Migration(migrations.Migration):
""" Migration to convert Foo into a polymorphic child of BaseItem
Since we are using UUID primary keys, we can reliably set them without
clobbering existing records. This approach would not be sufficient for
auto-incrementing integer primary keys.
This migration is NOT currently reversible, because when the ordered
operations of removing a primary key before adding a new one are reversed,
we have the removal of the *only* remaining primary key before the
restoration of the original.
dependencies = [
('contenttypes', '0001_initial'),
('myapp', '0001_initial'), # most recent app migration here
operations = [
# create a BaseItem instance for each of these Items, having the same ID
migrations.RunPython(seed_baseitem, migrations.RunPython.noop),
# Add the `baseitem_ptr` field (but nullable, not primary key)
field=models.OneToOneField(parent_link=True, auto_created=True, null=True, serialize=False, to='myapp.BaseItem'),
# copy `id` (and any additional relevant values) to `baseitem_ptr`
migrations.RunPython(populate_foo_baseitem_ptr, migrations.RunPython.noop),
# remove the original Foo primary key
# make Foo.baseitem_ptr NOTNULL, and set as primary key
field=models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='myapp.BaseItem'),
# run a RemoveField for any fields which are no longer needed, if data has been copied to corresponding BaseItem fields
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment