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

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

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


当前回答

试试这个

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

其他回答

如果你有一个OneToOneField,那么你应该这样做:

    tmp = Foo.objects.get(pk=1)
    tmp.pk = None
    tmp.id = None
    instance = tmp

克隆具有多个继承级别的模型,即>= 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)

请参考这里的问题。

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的回答中提到了将pk设置为None,尽管它没有显示在前面和中心。所以我的回答主要是为了强调这个方法是django推荐的方法。

历史提示:Django文档直到1.4版才解释了这一点。不过,在1.4之前就已经实现了。

未来可能的功能:前述的文档更改是在此票据中进行的。在ticket的评论线程中,也有一些关于为模型类添加内置复制功能的讨论,但据我所知,他们决定暂时不解决这个问题。所以这种“手动”的复制方式现在可能只能用了。

使用下面的代码:

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)

这将在内存中进行复制,您可以独立地进行突变。

original = CheckoutItem(title="test", ...)
copy = CheckoutItem()

for f in CheckoutItem._meta.fields:
   setattr(copy, f.attname, getattr(original, f.attname))

或者,作为一种方法:


    def clone(self):
        """Returns a clone of this instance."""

        clone = self.__class__()
        for f in self.__class__._meta.fields:
            setattr(clone, f.attname, getattr(self, f.attname))

        return clone