重复的Django模型实例和指向它的所有外键 [英] Duplicate Django Model Instance and All Foreign Keys Pointing to It
问题描述
我想在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屋!