重复的Django模型实例和指向它的所有外键 [英] Duplicate Django Model Instance and All Foreign Keys Pointing to It

查看:110
本文介绍了重复的Django模型实例和指向它的所有外键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Django模型上创建一个方法,称为 model.duplicate(),它与模型实例重复,包括指向它的所有外键。我知道你可以这样做:

I want to create a method on a Django model, call it model.duplicate(), that duplicates the model instance, including all the foreign keys pointing to it. I know that you can do this:

def duplicate(self):
   self.pk = None
   self.save()

...但是这样所有相关的模型仍然指向旧

...but this way all the related models still point to the old instance.

我不能简单地保存对原始对象的引用,因为 self 在执行期间指向更改的方法:

I can't simply save a reference to the original object because what self points to changes during execution of the method:

def duplicate(self):
    original = self
    self.pk = None
    self.save()
    assert original is not self    # fails

我可以尝试保存对相关对象的引用:

I could try to save a reference to just the related object:

def duplicate(self):
    original_fkeys = self.fkeys.all()
    self.pk = None
    self.save()
    self.fkeys.add(*original_fkeys)

...但是将它们从原始记录转移到新记录。我需要他们复制并指出新的记录。

...but this transfers them from the original record to the new one. I need them copied over and pointed at the new record.

其他地方(在此之前我更新了这个问题)的几个答案建议使用Python的 复制 ,我怀疑为外键工作>在这个模型上,而不是指向其他模型的外键。

Several answers elsewhere (and here before I updated the question) have suggested using Python's copy, which I suspect works for foreign keys on this model, but not foreign keys on another model pointing to it.

def duplicate(self):
    new_model = copy.deepcopy(self)
    new_model.pk = None
    new_model.save()

如果你这样做 new_model.fkeys.all()(跟随我的命名方案到目前为止)将是空的。

If you do this new_model.fkeys.all() (to follow my naming scheme thus far) will be empty.

推荐答案

您可以创建新的实例并将其另存为

You can create new instance and save it like this

def duplicate(self):
    kwargs = {}
    for field in self._meta.fields:
        kwargs[field.name] = getattr(self, field.name)
        # or self.__dict__[field.name]
    kwargs.pop('id')
    new_instance = self.__class__(**kwargs)
    new_instance.save()
    # now you have id for the new instance so you can
    # create related models in similar fashion
    fkeys_qs = self.fkeys.all()
    new_fkeys = []
    for fkey in fkey_qs:
        fkey_kwargs = {}
        for field in fkey._meta.fields:
            fkey_kwargs[field.name] = getattr(fkey, field.name)
        fkey_kwargs.pop('id')
        fkey_kwargs['foreign_key_field'] = new_instance.id
        new_fkeys.append(fkey_qs.model(**fkey_kwargs))
    fkeys_qs.model.objects.bulk_create(new_fkeys)
    return new_instance

我不知道它将如何与ManyToMany字段的行为。但是对于简单的字段,它可以工作。而且您可以随时弹出您对新实例不感兴趣的字段。

I'm not sure how it'll behave with ManyToMany fields. But for simple fields it works. And you can always pop the fields you are not interested in for your new instance.

我正在迭代的位 _meta.fields 可能会复制,但重要的是使用 id foreign_key_field

The bits where I'm iterating over _meta.fields may be done with copy but the important thing is to use the new id for the foreign_key_field.

我确定以编程方式检测哪些字段是 self的外键。_ class __ foreign_key_field ),但是由于您可以拥有更多的内容,因此更明确地指定一个(或更多)。

I'm sure it's programmatically possible to detect which fields are foreign keys to the self.__class__ (foreign_key_field) but since you can have more of them it'll better to name the one (or more) explicitly.

这篇关于重复的Django模型实例和指向它的所有外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆