In yuvi's answer manually assigning modelbase_ptr and saving fails since instance.modelbase_ptr is deleted prior to save.
Building on yuvi's answer here a more explicit example and works generically for abstract and non-abstract conversions of:
- ModelBase -> ModelChild
- ModelChild -> ModelBase
- ModelChild -> ModelChild
Optionally preserves the original id and this follows the django docs recomended methodology.
ex_model = ModelA
new_model = ModelB
ex_instance = ex_model.objects.get(pk=1) #arbitrary
# find fields required for new_model:
new_fields = [f.name for f in new_model._meta.fields]
# make new dict of existing field : value
new_fields_dict = dict( [(x, getattr(ex_instance, x, None)) for x in new_fields] )
# Save temp copy as new_model with new id
# modelbase_ptr will be created automatically as required
new_fields_dict.pop('project_ptr', None)
temp_instance = new_model(**new_fields_dict)
temp_instance.pk = None
temp_instance.id = None
temp_instance.save()
# you must set all your related fields here
temp_instance.copy_related(ex_instance)
ex_instance.delete()
# (optional) Save final copy as new_model with original id
final_instance = new_model(**new_fields_dict)
final_instance.save()
final_instance.copy_related(temp_instance)
temp_instance.delete()
# here are the removed fields, handle as required
removed_fields = [f.name for f in ex_model._meta.fields if f.name not in new_fields_dict.keys()]
removed_fields_dict = dict( [(x, getattr(ex_instance, x, None)) for x in removed_fields] )
In Class ModelBase:
def copy_related(self, from):
# include all your related fields here
self.related_field = from.related_field.all()
self.related_field_a = from.related_field_a.all()