在Django中将字段从一个实例复制到另一个实例

时间:2014-11-17 14:34:02

标签: python django

我有以下代码,它将现有实例和副本或“归档”它放在另一个模型中,然后删除它,用草稿副本替换它。

当前代码

def archive_calc(self, rev_num, primary_field):
    model_a = Calc.objects.get(tag_number__tag_number = primary_field, revision_number = rev_num) #Current Revision instance
    model_b = CalcArchive() #Draft instance

    #Copies data to archive model
    for field in model_a._meta.fields:
        setattr(model_b, field.name, getattr(model_a, field.name))

    model_b.pk = None
    model_b.current_revision = False
    model_b.save()

    model_a.delete()

这很好但是我需要更改系统以允许某些具有外键的模型,因为当存档/删除实例时,相关记录将随之删除。因此,我想解决这个问题的方法是将草稿记录中的更改复制到上一条记录中,然后删除草稿,从而维护外键相关记录。

解决方案想法

def archive_calc(self, rev_num, primary_field):
    model_a = Calc.objects.get(tag_number__tag_number = primary_field, revision_number = rev_num) #Current Revision instance
    model_b = CalcArchive() #Archive Instance
    model_c = Calc.objects.get(pk = self.object.pk) #Draft instance

    #Copies data to archive model
    for field in model_a._meta.fields:
        setattr(model_b, field.name, getattr(model_a, field.name))

    model_b.pk = None
    model_b.current_revision = False
    model_b.save()

    #Copies data from draft instance to current revision instance
    for field in model_c._meta.fields:
        setattr(model_a, field.name, getattr(model_c, field.name))

    model_c.delete()

不幸的是,上述解决方案不起作用,它似乎忽略了副本并继续按照“当前代码”工作。如果我在model_a.save()之后添加for field in model_c._meta.fi...,系统会陷入循环并最终抛出maximum recursion depth exceeded in cmp

任何帮助都会像往常一样欣赏,如果我咆哮错误的树,请告诉我。

3 个答案:

答案 0 :(得分:1)

经过大量的阅读和阅读Django文档后,我想出了一个非常好的,简单的解决方案。

def archive_calc(self, rev_num, primary_field):
    model_a = Calc.objects.get(calc_details__calc_serial_number = primary_field, revision_number = rev_num)
    model_b = CalcArchive()

    object_list_annual = model_a.calcreview_set.filter(calc__calc_details = primary_field)
    object_list_ageing = model_a.calcitem_set.filter(calc__calc_details = primary_field)

    for obj in object_list_annual:
        obj.calc_id = self.object.id
        obj.save()
    for obj in object_list_ageing:
        obj.calc_id = self.object.id
        obj.save()

    for field in model_a._meta.fields:
        setattr(model_b, field.name, getattr(model_a, field.name))
    model_b.pk = None
    model_b.current_revision = False
    model_b.save()

    model_a.delete()

这个'移动'通过将_id字段设置为与self.object.id相同的相关对象。

我已经进行了多次测试,这似乎达到了我想要的最少的代码,没有额外的安装。

希望这对某人有所帮助,请随时指出我的答案中可能存在的任何陷阱。

答案 1 :(得分:0)

obj = Model.objects.get(pk=1)
obj.pk = get_unused_pk()
obj.save()

您只需要更改主键(我不知道您应该如何在数据库模式中对其进行评估)并保存模型实例。

答案 2 :(得分:0)

听起来你想要深刻复制'模型实例。

Django-forkit应该可以做到这一点。

看起来它复制了ForeignKeys而不是ManyToManyFields,希望这对你没问题:

  

对于深度重置,将遍历并重置直接外键。   不会尝试重置多对多和反向外键   因为相关对象之间的比较供参考和   例如,相关的对象变得模棱两可。