在django中将一个子类模型实例转换为另一个子类模型实例?

在django中将一个子类模型实例转换为另一个子类模型实例?,django,model,Django,Model,我有一个模型库,模型a,模型B 我想将ModelA实例更改为ModelB实例。我可以处理他们不同的属性 我见过相关的问题,但对我来说不太合适 编辑 当你有地方-餐厅/酒吧关系时, 我认为把餐馆换成酒吧是很合理的 我将创建第二个模型的一个全新实例,其共享属性值相同,然后删除旧的实例。对我来说似乎是最干净的方式 如果ModelBase是抽象的: instance = ModelA.objects.get(pk=1) #arbitrary # find parent class

我有一个模型库,模型a,模型B

我想将ModelA实例更改为ModelB实例。我可以处理他们不同的属性

我见过相关的问题,但对我来说不太合适

编辑 当你有地方-餐厅/酒吧关系时,
我认为把餐馆换成酒吧是很合理的

我将创建第二个模型的一个全新实例,其共享属性值相同,然后删除旧的实例。对我来说似乎是最干净的方式

如果ModelBase是抽象的:

instance = ModelA.objects.get(pk=1) #arbitrary        

# find parent class fields:
fields = [f.name for f in ModelBase._meta.fields]

# get the values from the modelA instance
values = dict( [(x, getattr(instance, x)) for x in fields] )

#assign same values to new instance of second model
new_instance = ModelB(**values) 

#add any additional information to new instance here

new_instance.save() #save new one
instance.delete() # remove the old one
但是,如果ModelBase不是抽象的,则必须进行额外的变通:

fields = [f.name for f in ModelBase._meta.fields if f.name != 'id']
#... other parts are the same...

new_instance.modelbase_ptr = instance.modelbase_ptr #re-assign related parent
instance.delete() #delete this first!
new_instance.save()

我将创建第二个模型的一个全新实例,其共享属性值相同,然后删除旧的实例。对我来说似乎是最干净的方式

如果ModelBase是抽象的:

instance = ModelA.objects.get(pk=1) #arbitrary        

# find parent class fields:
fields = [f.name for f in ModelBase._meta.fields]

# get the values from the modelA instance
values = dict( [(x, getattr(instance, x)) for x in fields] )

#assign same values to new instance of second model
new_instance = ModelB(**values) 

#add any additional information to new instance here

new_instance.save() #save new one
instance.delete() # remove the old one
但是,如果ModelBase不是抽象的,则必须进行额外的变通:

fields = [f.name for f in ModelBase._meta.fields if f.name != 'id']
#... other parts are the same...

new_instance.modelbase_ptr = instance.modelbase_ptr #re-assign related parent
instance.delete() #delete this first!
new_instance.save()

在yuvi的回答中,手动分配modelbase_ptr并保存失败,因为instance.modelbase_ptr在保存之前被删除

在yuvi的回答的基础上,这里有一个更明确的示例,通常用于以下的抽象和非抽象转换:

ModelBase->ModelChild ModelChild->ModelBase ModelChild->ModelChild (可选)保留原始id,并遵循推荐的方法

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] )
类内模型库:

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()

在yuvi的回答中,手动分配modelbase_ptr并保存失败,因为instance.modelbase_ptr在保存之前被删除

在yuvi的回答的基础上,这里有一个更明确的示例,通常用于以下的抽象和非抽象转换:

ModelBase->ModelChild ModelChild->ModelBase ModelChild->ModelChild (可选)保留原始id,并遵循推荐的方法

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] )
类内模型库:

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()

我必须处理同样的问题,yuvi和arctelix的答案对我来说都不起作用。yuvi解决方案给出一个错误,arctelix解决方案使用新pk创建新对象

这里的目标是更改子类模型,同时保持原始超类与旧pk的原样

首先:删除旧的子类并保留超类。检查

第二:添加新的子类及其字段,并将超类传递给它。 检查

示例:一个地方可以是餐厅或咖啡馆,您希望将餐厅位置更改为咖啡馆;详情如下:

class Place(models.Model):
            name = models.CharField(max_length=50)
            address = models.CharField(max_length=80)

class Caffe(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

class Restaurant(Place):
    serves_tea = models.BooleanField(default=False)
    serves_coffee = models.BooleanField(default=False)

# get the objecte to be changed
rest = Restaurant.objects.get(pk=1) #arbitrary number
#delete the subclass while keeping the parent
rest.delete(keep_parents=True)

place = Place.objects.get(pk=1) # the primary key must be the same as the deleted restaurant

# Create a caffe and pass the original place
caffee = Caffe(place_ptr_id=place.pk) #this will empty the parent field

#update parent fields
caffee.__dict__.update(place.__dict__)

#add other field
........

#save the caffe
caffee.save()

我必须处理同样的问题,yuvi和arctelix的答案对我来说都不起作用。yuvi解决方案给出一个错误,arctelix解决方案使用新pk创建新对象

这里的目标是更改子类模型,同时保持原始超类与旧pk的原样

首先:删除旧的子类并保留超类。检查

第二:添加新的子类及其字段,并将超类传递给它。 检查

示例:一个地方可以是餐厅或咖啡馆,您希望将餐厅位置更改为咖啡馆;详情如下:

class Place(models.Model):
            name = models.CharField(max_length=50)
            address = models.CharField(max_length=80)

class Caffe(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

class Restaurant(Place):
    serves_tea = models.BooleanField(default=False)
    serves_coffee = models.BooleanField(default=False)

# get the objecte to be changed
rest = Restaurant.objects.get(pk=1) #arbitrary number
#delete the subclass while keeping the parent
rest.delete(keep_parents=True)

place = Place.objects.get(pk=1) # the primary key must be the same as the deleted restaurant

# Create a caffe and pass the original place
caffee = Caffe(place_ptr_id=place.pk) #this will empty the parent field

#update parent fields
caffee.__dict__.update(place.__dict__)

#add other field
........

#save the caffe
caffee.save()

确保这是您想要的,因为没有好的方法。确保这是您想要的,因为没有好的方法。谢谢,我如何处理指向已删除实例的外键?我没有看到您的模型,因此无法确切地告诉您如何处理,但是,在删除旧实例之前,您只需将它们重新指向新的_实例,就像我在第二个示例中对父模块所做的那样。哦。。实际上,指针不具有已删除的父对象的id吗?不是删除的?我有点不明白你的意思,但我可以告诉你,我验证了解决方案,相关模型的重新分配对我有效。当某些东西引用旧的_实例时,它不会有modelbase的id吗?当modelbase不是抽象的时候。这就是我的意思。谢谢,我如何处理指向已删除实例的外键?我还没有看到您的模型,所以我无法确切地告诉您如何处理,但您只需在删除旧实例之前将它们重新指向新实例,就像我在第二个示例中对父模块所做的那样。哦。。实际上,指针不具有已删除的父对象的id吗?不是删除的?我有点不明白你的意思,但我可以告诉你,我验证了解决方案,相关模型的重新分配对我有效。当某些东西引用旧的_实例时,它不会有modelbase的id吗?当modelbase不是抽象的时候。这就是我的意思。