Migrating existing models to polymorphic

Existing models can be migrated to become polymorphic models. During the migrating, the polymorphic_ctype field needs to be filled in.

This can be done in the following steps:

  1. Inherit your model from PolymorphicModel.
  2. Create a Django migration file to create the polymorphic_ctype_id database column.
  3. Make sure the proper ContentType value is filled in.

Filling the content type value

The following Python code can be used to fill the value of a model:

from django.contrib.contenttypes.models import ContentType
from myapp.models import MyModel

new_ct = ContentType.objects.get_for_model(MyModel)
MyModel.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=new_ct)

The creation and update of the polymorphic_ctype_id column can be included in a single Django migration. For example:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models


def forwards_func(apps, schema_editor):
    MyModel = apps.get_model('myapp', 'MyModel')
    ContentType = apps.get_model('contenttypes', 'ContentType')

    new_ct = ContentType.objects.get_for_model(MyModel)
    MyModel.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=new_ct)


class Migration(migrations.Migration):

    dependencies = [
        ('contenttypes', '0001_initial'),
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='mymodel',
            name='polymorphic_ctype',
            field=models.ForeignKey(related_name='polymorphic_myapp.mymodel_set+', editable=False, to='contenttypes.ContentType', null=True),
        ),
        migrations.RunPython(forwards_func, migrations.RunPython.noop),
    ]

It’s recommended to let makemigrations create the migration file, and include the RunPython manually before running the migration.

New in version 1.1.

When the model is created elsewhere, you can also use the polymorphic.utils.reset_polymorphic_ctype() function:

from polymorphic.utils import reset_polymorphic_ctype
from myapp.models import Base, Sub1, Sub2

reset_polymorphic_ctype(Base, Sub1, Sub2)

reset_polymorphic_ctype(Base, Sub1, Sub2, ignore_existing=True)