如何克隆Django模型实例并保存到数据库?

375 投票
15 回答
216973 浏览
提问于 2025-04-16 10:14
Foo.objects.get(pk="foo")
<Foo: test>

在数据库里,我想添加一个新对象,这个对象是上面那个对象的复制品。

假设我的表里有一行数据。我想把第一行的对象插入到另一行里,但要有一个不同的主键。那我该怎么做呢?

15 个回答

64

这里要小心。如果你在某个循环里一个一个地获取对象,这样做可能会非常耗费资源。如果你不想去数据库查询,可以直接这样做:

from copy import deepcopy

new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()

这样做的效果和其他一些答案是一样的,但它不会去数据库里查询对象。如果你想复制一个在数据库中还不存在的对象,这个方法也很有用。

167

Django的数据库查询文档里有一部分讲的是如何复制模型实例,具体可以查看这段内容。假设你的主键是自动生成的,你只需要找到想要复制的对象,把它的主键设置为None,然后再保存这个对象:

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1

blog.pk = None
blog.save() # blog.pk == 2

在这个代码片段中,第一次调用save()是用来创建原始对象的,第二次调用save()则是用来创建复制对象的。

如果你继续阅读文档,还会看到如何处理两个更复杂的情况:(1) 复制一个模型子类的实例,(2) 复制相关对象,包括多对多关系中的对象。


关于miah的回答:虽然miah的回答中提到了将主键设置为None,但并没有特别强调。所以我这里主要是想强调这种方法是Django推荐的做法。

历史说明:在Django文档中,直到1.4版本才解释了这个内容,但在1.4之前其实就已经可以做到这一点了。

未来可能的功能:前面提到的文档更改是在这个问题单中进行的。在讨论中也提到过是否要为模型类添加一个内置的copy函数,但据我所知,他们决定暂时不解决这个问题。所以现在可能还是得用这种“手动”的方式来复制。

651

只需要改变你对象的主键,然后运行保存操作(save())。

obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()

如果你想要自动生成的主键,可以把新的主键设置为None。

关于更新和插入的更多信息,可以在这里查看。

官方文档关于复制模型实例的内容在这里:https://docs.djangoproject.com/en/2.2/topics/db/queries/#copying-model-instances

撰写回答