[Django]-Change the polymorphic content type of a django model instance

4👍

Ok.

After reading this similar post I realized that I needed another assignment:

foo.__class__ = Child

This makes an insertion in the child table otherwise never happened.

0👍

Django will automatically duplicate entries into the Child in the Father. For the migration that creates the Child class you can simply save new Child objects in the DB (populating them using the __dict__ property of the python object):

Define this function in your migrate file:

def duplicate_Children(apps,schema_editor):
    Father = apps.get_model('myapp','Father')
    Child= apps.get_model('myapp','Child')
    for dad in Father.objects.all():
         son = Child()

         for attr in dad.__dict__:
             son.__dict__[attr]=dad.__dict__[attr]

         son.save()

...

Add this to the operations list in the Migrate class:

operations = [migrations.RunPython(duplicate_Children)]

0👍

For polymorphic model yo can do this:

kclass = YourChangeClass
# With that do the correct insert
self.__class__ = kclass
# With that change the correct model
ct = ContentType.objects.get_for_model(kclass)
self.polymorphic_ctype = ct
# With that set the default values
self.set_default_values()
self.save()

Yo need to define for every class a method that define default values because in other way when do save() fail!.

For example, if you need to pass from A to B:

class A():
    attr_1
class B()
    attr_2
    def set_default_values(self):
        self.attr_2 = None

0👍

I had trouble with the previous solutions, but based on this post, here’s a solution that works with Django-Polymorphic:

ContentType = apps.get_model("contenttypes.ContentType")

queryset = Parent.objects.filter(...)

for parent in queryset:
    # parent_ptr is generated from the name of the parent model
    child = Child(parent_ptr=parent, ...)
    child.save_base(raw=True)

# Change the type in Django-Polymorphic
content_type = ContentType.objects.get_for_model(Child)
queryset.update(polymorphic_ctype=content_type)

Leave a comment