How do I clone a Django model instance object and save it to the database?
1 2 | Foo.objects.get(pk="foo") <Foo: test> |
在数据库中,我想添加另一个对象,它是上面对象的副本。
假设我的桌子只有一行。我想用不同的主键将第一行对象插入另一行。我该怎么做?
只需更改对象的主键并运行save()。
1 2 3 | obj = Foo.objects.get(pk=<some_existing_pk>) obj.pk = None obj.save() |
如果需要自动生成的键,请将新键设置为"无"。
有关更新/插入的详细信息。
用于数据库查询的Django文档包括一个关于复制模型实例的部分。假设您的主键是自动生成的,您将得到要复制的对象,将主键设置为
1 2 3 4 5 | blog = Blog(name='My blog', tagline='Blogging is easy') blog.save() # blog.pk == 1 blog.pk = None blog.save() # blog.pk == 2 |
在这段代码中,第一个
如果您继续阅读文档,还有一些关于如何处理两个更复杂的情况的示例:(1)复制一个属于模型子类实例的对象;(2)还复制相关对象,包括多对多关系中的对象。
关于Miah的回答,请注意:在Miah的回答中提到了将pk设置为
历史记录:直到1.4版,Django文档才解释这一点。不过,从1.4之前就有可能了。
可能的未来功能:上述文档更改是在此票据中进行的。在Ticket的评论线程中,也有一些关于为模型类添加一个内置的
这里要小心。如果你在某个循环中,并且一个接一个地检索对象,那么这会非常昂贵。如果不想调用数据库,只需执行以下操作:
1 2 3 4 5 | from copy import deepcopy new_instance = deepcopy(object_you_want_copied) new_instance.id = None new_instance.save() |
它与其他一些答案的作用相同,但它不会调用数据库来检索对象。如果要复制数据库中还不存在的对象,这也很有用。
使用以下代码:
1 2 3 4 5 6 | from django.forms import model_to_dict instance = Some.objects.get(slug='something') kwargs = model_to_dict(instance, exclude=['id']) new_instance = Some.objects.create(**kwargs) |
这里有一个克隆片段,您可以将其添加到模型中,这样做:
1 2 3 | def clone(self): new_kwargs = dict([(fld.name, getattr(old, fld.name)) for fld in old._meta.fields if fld.name != old._meta.pk]); return self.__class__.objects.create(**new_kwargs) |
如何做到这一点已添加到Django1.4的官方Django文档中。
https://docs.djangoproject.com/en/1.10/topics/db/queries/复制模型实例
官方答案与Miah的答案类似,但文档指出了继承和相关对象的一些困难,因此您可能应该确保阅读文档。
将pk设置为none更好,因为django可以为您正确创建pk
1 2 3 | object_copy = MyObject.objects.get(pk=...) object_copy.pk = None object_copy.save() |
我遇到了一对有着公认答案的人。这是我的解决方案。
1 2 3 4 5 6 7 8 9 10 | import copy def clone(instance): cloned = copy.copy(instance) # don't alter original instance cloned.pk = None try: delattr(cloned, '_prefetched_objects_cache') except AttributeError: pass return cloned |
注意:这使用了Django文档中没有正式批准的解决方案,它们在未来的版本中可能会停止工作。我在1.9.13测试过这个。
第一个改进是,它允许您通过使用
其次,已批准的答案将保留附加到新实例的任何预取结果。除非显式地将复制到多个关系,否则这些结果不应与新实例关联。如果遍历预取关系,将得到与数据库不匹配的结果。在添加预取时破坏工作代码可能是一个令人讨厌的惊喜。
删除
这是克隆模型实例的另一种方法:
1 2 3 | d = Foo.objects.filter(pk=1).values().first() d.update({'id': None}) duplicate = Foo.objects.create(**d) |
试试这个
1 2 3 4 5 | original_object = Foo.objects.get(pk="foo") v = vars(original_object) v.pop("pk") new_object = Foo(**v) new_object.save() |
克隆具有多个继承级别的模型,即:>=2或下面的ModelC
1 2 3 4 5 6 7 8 | class ModelA(models.Model): info1 = models.CharField(max_length=64) class ModelB(ModelA): info2 = models.CharField(max_length=64) class ModelC(ModelB): info3 = models.CharField(max_length=64) |
请在这里提出问题。