【问题标题】:django-reversion undo feature - recovering multiple objectsdjango-reversion 撤消功能 - 恢复多个对象
【发布时间】:2013-03-12 10:50:12
【问题描述】:

我正在尝试使用 django-reversion 在 django 项目中实现“撤消”功能,以防用户意外修改多个对象。使用管理面板将无法正常工作,因为必须逐个还原对象。

我的问题是我无法创建包含多个对象数据的修订版。
即使我这样做了

with reversion.create_revision():
    Res.object.all().delete()

然后我无法访问分组此更改的修订。它以“一个对象一个版本.models.Version”的方式进行拆分。

In [103]: reversion.models.Version.objects.all()
Out[103]: [<Version: #00001>, <Version: #00002>]

我也试过了

reversion.models.Revision.objects.all().order_by('-date_created')[0].version_set.all()

但它也只为一个已删除的 Res 对象返回了一个版本。 好像我错过了什么。

【问题讨论】:

    标签: python django undo django-reversion


    【解决方案1】:

    tl;dr - 修订不是你“撤消”的东西。这是你恢复的东西。因此,撤消是找到在您要撤消的内容之前发生的最新修订,并通过调用 revert() 恢复它。

    django-reversion 的数据模型基于修订和版本。一个 Revision 由一个或多个 Version 组成,一个 Version 代表一个 Django 模型的序列化状态。

    django-reversion 允许您回滚到任何先前版本或修订的状态。这与撤消功能相似但不完全相同。

    考虑以下工作流程:

    # Create a Revision containing two Versions.
    with reversion.create_revision():
        a = SomeModel.objects.create(name="A version 1")
        b = SomeModel.objects.create(name="B version 1")
    
    # Create a Revision containing to Versions.
    with reversion.create_revision():
        a.name = "A version 2"
        a.save()
        b.name = "B version 2"
        b.save()
    

    此时,您可以通过恢复到上一个​​版本来“撤消”第二次编辑。

    # Revert just 'a' to version 1. This is the last but one revision.
    reversion.get_for_object(a)[1].revert()
    
    # Or, revert 'a' and 'b' to version 1.
    reversion.get_for_object(b)[1].revision.revert()
    

    您也可以像这样删除和恢复:

    # Store the pk of 'a', then delete it.
    a_pk = a.pk
    a.delete()
    
    # Recover 'a' via it's primary key.
    reversion.get_deleted(SomeModel).filter(object_id=a_pk).revert()
    

    因此,您可以恢复到单个模型或一起保存的一组模型的先前状态。但是,没有办法说“撤消我刚刚所做的”。相反,你必须告诉 reversion '变得像你当时的样子'。

    在您的情况下,如果您想撤消批量删除,您可以这样做:

    # Save a revision containing all SomeModel instances.
    with reversion.create_revision():
        for obj in SomeModel.objects.all():
            obj.save()
    
    # Delete them all.
    SomeModel.objects.delete()
    
    # Revert back to the previous revision, where nothing was deleted.
    Revision.objects.filter(version__content_type=ContentType.objects.get_for_model(SomeModel)).order_by("-date_created")[0].revert()
    

    但是,在这种情况下,您会遇到一个非常愚蠢的竞争条件,因为 SomeModel 的其他修订版可能随时创建。

    【讨论】:

    • 我仍然无法获得将批量更改分组到模型实例的修订版。我尝试了您的工作流程,将实例保存到修订版中,然后对它们执行 delete() - 每个模型都有一个修订版,并且 version_set 仅对相关模型进行分组。 pastebin.com/UHKQ32ae
    • 道歉...我错字了,我已经修改了。
    • 感谢您的澄清,但通过内容类型过滤器获取修订不会导致将更改分组到多个模型实例的修订。我只剩下每个实例一个修订,并考虑在修订/版本上使用基于哈希/时间戳/用户名的 cmets 进行一些丑陋的 hack,以将它们组合在一起。
    【解决方案2】:

    我终于明白了。

    问题 1:将与多个对象相关的更改存储在单个修订版中

    解决方案:将 TransactionMiddleware 添加到 MIDDLEWARE_CLASSES

    问题 2:撤消功能/还原更改

    嗯,这很令人困惑。您不能还原更改,您可以恢复对象到以前已知的状态。并且在您的对象更改视图中使用 reversion.create_revision() 来存储关于该对象更改后的数据。如果您有修改多个对象的视图,那么您必须在进行实际更改之前创建修订。

    这在管理面板中也可见。如果您更改对象,则会出现一个新的日志条目。但是,如果您想恢复该更改而不是选择最新版本 - 它与对象的当前状态相同 - 而您必须选择 previous 一个。

    【讨论】:

      猜你喜欢
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      • 2019-02-17
      • 2011-09-26
      • 2017-03-10
      • 2014-02-07
      • 2011-01-26
      • 1970-01-01
      相关资源
      最近更新 更多