复制后重命名 Dexterity 对象 (id)

Rename Dexterity object (id) after copy

使用 INameChooser 在创建时选择对象 ID 很简单。 但我们也希望能够在克隆后选择对象 ID(并避免在对象 ID 中使用 copy_of)。

我们尝试了几种不同的解决方案:

每次,我们都会收到回溯,因为我们“过早”更改了 ID。例如当使用 Plone API :

  File "/Users/laurent/.buildout/eggs/plone.api-2.0.0a1-py3.7.egg/plone/api/content.py", line 256, in copy
    return target[new_id]
  File "/Users/laurent/.buildout/eggs/plone.folder-3.0.3-py3.7.egg/plone/folder/ordered.py", line 241, in __getitem__
    raise KeyError(key)
KeyError: 'copy_of_87c7f9b7e7924d039b832d3796e7b5a3'

或者,在 Plone 实例中使用复制/粘贴:

  Module plone.app.content.browser.contents.paste, line 42, in __call__
  Module OFS.CopySupport, line 317, in manage_pasteObjects
  Module OFS.CopySupport, line 229, in _pasteObjects
  Module plone.folder.ordered, line 73, in _getOb
AttributeError: 'copy_of_a7ed3d678f2643bc990309cde61a6bc5'

这是合乎逻辑的,因为 ID 在事件通知/manage_afterClone 调用之前存储以备后用。

即使在容器上定义 _get_id 也无法定义 ID,因为我们没有从中获取属性(并生成 ID)的对象。

但是,我们怎样才能以干净的方式实现这一目标呢? 请告诉我有比重新定义 _pasteObjects (OFS.CopySupport) !

更好的解决方案

感谢您的意见!

很遗憾不是...

但是您可以从 _get_id.

中访问原始对象

例如:

from OFS.CopySupport import _cb_decode
from plone import api

    ...
    def _get_id(self, id_):
        # copy_or_move => 0 means copy, 1 means move
        copy_or_move, path_segments = _cb_decode(self.REQUEST['__cp']
        source_path = '/'.join(path_segments[0])  # Imlement for loop for more than one copied obj.
        app = self.getPhysicalRoot()

        # access to source obj
        source_obj = app.restrictedTraverse(source_path)
        # Do whatever you need - probably using INameChooser
    ....

为了有一个规范的修补方法,我使用 collective.monkeypatcher

安装后在 ZCML 中添加以下内容:

  <include package="collective.monkeypatcher" />

  <monkey:patch
      class="OFS.CopySupport.CopyContainer"
      original="_get_id"
      replacement="patches.patched_get_id"
      />

其中 patches.py 是包含新方法 patched_get_id 的模块,它取代了 _get_id.

很抱歉,我没有更好的消息告诉您,但这就是我解决类似需求的方法。

此代码 (patched _get_id) 在 id 的末尾添加一个计数器(如果已经存在的话)。


def patched_get_id(self, id_)
    match = re.match('^(.*)-([\d]+)$', id_)
    if match:
        id_ = match.group(1)
        number = int(match.group(2))
    else:
        number = 1
    
    new_id = id_
    while new_id in self.objectIds():
        new_id = '{}-{}'.format(id_, number)
        number += 1
    return new_id