Foo.objects.get(pk="foo")
<Foo: test>

在数据库中,我想添加另一个对象,这是上面对象的副本。

假设我的表只有一行。我想将第一行对象插入到另一行,使用不同的主键。我该怎么做呢?


当前回答

使用下面的代码:

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)

其他回答

克隆具有多个继承级别的模型,即>= 2,或ModelC以下

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)

请参考这里的问题。

试试这个

original_object = Foo.objects.get(pk="foo")
v = vars(original_object)
v.pop("pk")
new_object = Foo(**v)
new_object.save()

这是克隆模型实例的另一种方式:

d = Foo.objects.filter(pk=1).values().first()   
d.update({'id': None})
duplicate = Foo.objects.create(**d)

设置pk为None更好,因为Django可以正确地为你创建一个pk

object_copy = MyObject.objects.get(pk=...)
object_copy.pk = None
object_copy.save()

我在公认的答案中遇到了一些问题。这是我的解决方案。

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测试了这个功能。

第一个改进是,它允许您通过copy.copy继续使用原始实例。即使您不打算重用实例,如果您要克隆的实例是作为参数传递给函数的,那么执行这一步会更安全。否则,当函数返回时,调用者将意外地拥有一个不同的实例。

副本。copy似乎以所需的方式生成Django模型实例的浅拷贝。这是我没有找到文档的东西之一,但它通过pickle和unpickle工作,因此可能得到了良好的支持。

其次,已批准的答案将把任何预取的结果附加到新实例。这些结果不应该与新实例相关联,除非显式地复制“多到多”关系。如果遍历预取的关系,将得到与数据库不匹配的结果。当您添加预取时,破坏工作代码可能是一个令人讨厌的惊喜。

删除_prefetched_objects_cache是去除所有预取的一种快速而肮脏的方法。后续的多路访问就像从来没有预取一样。使用以下划线开头的未记录的属性可能会带来兼容性问题,但目前是可行的。