1

我正在开发一个项目,该项目使用 django-reversion 来跟踪更改并提供恢复到早期状态的能力,并使用 django-mptt 来处理一些树形模型。然而,删除和恢复功能有一些奇怪的行为。我正在使用如下所示的演示数据:

Big Company
    Sub Company 1
    Sub Company 2
      Tiny Company 1
      Tiny Company 2

我已经操纵了 django-reversion 以便删除一个节点也会将其所有子节点保存到修订版中——因此,删除 Big Company 会删除整个树,然后还原它(或者实际上是任何子节点)也会还原整棵树。到目前为止,一切都很好。

然而,当我尝试删除/恢复子节点时,事情开始变得奇怪。例如,删除“子公司 1”会导致“子公司 2”及其后代停止在模板中呈现(尽管奇怪的是,这种行为有些不一致)。或者,我是否应该在删除后使用 django-reversion 恢复“子公司 2”,“小公司”都不会在模板中呈现(尽管快速进入shell并调用对象表明它们仍在数据库中,并且他们仍然将“子公司 2”作为其母公司。

所有这些问题都可以通过调用来解决Company.objects.rebuild(),这会将树恢复到正确的表示形式——但是这个项目的生产就绪版本可能在数据库中有很多数据,而且由于这是一个全表活动,所以它会令人望而却步昂贵的。关于我可以做些什么来解决这个问题的任何想法?

4

1 回答 1

2

好吧,我找到了一种让它工作的方法。我不是简单地删除 MPTT 节点,而是将其移动到新的根位置。这会以一种似乎不会简单地删除节点的方式正确地重新组织树。当然,我希望能够在之后重新附加节点,因此我将父主键存储在补充修订元数据选项中。相关代码如下所示:

class MPTT_Parent(models.Model):
    revision = models.OneToOneField(Revision)
    parent_id = models.IntegerField()

def remove_company(obj):
    with transaction.atomic() and reversion.create_revision():

         #These lines are to preserve the integrity of the tree before deleting it
         #Objects deleted from django-mptt trees don't automatically update the positions
        if not obj.is_root_node():
            reversion.add_meta(MPTT_Parent,parent_id=obj.parent.id)
        obj.move_to(target=None,position='first-child')

        obj.save()

        #Save all associated descendant information into the revision
        for child in obj.get_descendants(include_self=False):
            child.save()

   obj.delete()

def restore_company(version):
    #get the parent id.  If the parent has been deleted or was never set, 
    #keeps the node as root
    company = revert_object(version) #custom function that reverts given object
    try:
         parent = Company.objects.get(id=version.revision.mptt_parent.parent_id)
    except (ObjectDoesNotExist, AttributeError):
         pass
    else:
         company.move_to(target=parent,position='first-child')

    return company
于 2014-08-09T16:55:20.567 回答