我有一个ModelBase和ModelA,ModelB。
我想将ModelA实例更改为ModelB实例。 (我可以处理他们所拥有的属性的差异)
我看过相关的问题,但对我来说并不适用。
How can I create an inherited django model instance from an existing base model instance?
Change class of child on django models
当你有Place - 餐厅/酒吧关系时,
我认为将餐厅换成酒吧是很合理的。
答案 0 :(得分:1)
我将使用相同的共享属性值创建第二个模型的全新实例,然后删除旧的实例。对我来说似乎是最干净的方式。
如果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()
答案 1 :(得分:0)
在yuvi的回答中,手动分配modelbase_ptr并保存失败,因为在保存之前删除了instance.modelbase_ptr。
建立在yuvi的答案这里是一个更明确的例子,并且通常用于抽象和非抽象的转换:
可选择保留原始ID,这遵循django docs推荐的方法。
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] )
在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()
答案 2 :(得分:0)
我不得不处理相同的问题,yuvi和arctelix的答案都对我不起作用。 yuvi解决方案出现错误,arctelix解决方案使用新的pk创建新对象。
这里的目标是更改子类模型,同时保持原始超类与旧pk相同。
首先:删除 old 子类并保留超类。选中Django documents。
第二:添加新的子类及其字段,并将超类传递给它。 选中this q
示例:一个地点可能是餐馆或咖啡馆,而您想将餐馆地点改为咖啡馆。如下:
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()