【问题标题】:Copy fields from one instance to another in Django在Django中将字段从一个实例复制到另一个实例
【发布时间】:2014-11-17 14:34:01
【问题描述】:

我有以下代码,它采用现有实例并将其复制或“归档”到另一个模型中,然后将其删除,并将其替换为草稿副本。

当前代码

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()

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

如往常一样,任何帮助将不胜感激,如果我叫错了树,请告诉我。

【问题讨论】:

标签: python django


【解决方案1】:
obj = Model.objects.get(pk=1)
obj.pk = get_unused_pk()
obj.save()

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

【讨论】:

  • 感谢您的评论。我需要更改哪个实例?我试图将“草稿”实例的“pk”设置为“当前修订版”中的“pk”,但相关对象/记录仍被删除。
  • 这不会复制不同模型(即相关字段)上的关系
【解决方案2】:

经过大量的探索和阅读 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 相同来“移动”相关对象。

我进行了几次测试,这似乎完全符合我的要求,只需最少的代码且无需额外安装。

希望这对某人有所帮助,请随时指出我的回答中的任何潜在缺陷。

【讨论】:

    【解决方案3】:

    听起来你想“深拷贝”一个模型实例。

    Django-forkit 应该可以解决问题。

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

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

    【讨论】:

    • 谢谢,我正在查看深拷贝,但看不到它是如何工作的。我刚刚下载了 Forkit,所以我让你知道我是怎么上手的,但是文档似乎有点薄! :)
    • 如果它没有给你你想要的东西,试试这个帖子:stackoverflow.com/questions/437166/…
    猜你喜欢
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多