如何清理zc.relation目录中的旧接口?

时间:2013-11-29 16:52:31

标签: plone dexterity

我在Plone 4.2.5中使用plone.directives.form版本1.0,升级到4.2.6后,我开始看到以下追溯,并且由于plone.directives.form而我猜测升级到1.1版。

如何避免此错误?唯一不是来自追踪中默认Plone的代码行位于der.freitag.handlers,其中transaction.commit()执行1385740390.020.496977141203 http://10.100.0.207:8081/website/front-page/atomkraft/++add++der.freitag.customizablearticlelink Traceback (innermost last): Module ZPublisher.Publish, line 138, in publish Module ZPublisher.mapply, line 77, in mapply Module ZPublisher.Publish, line 48, in call_object Module plone.z3cform.layout, line 70, in __call__ Module plone.z3cform.layout, line 54, in update Module plone.dexterity.browser.add, line 112, in update Module plone.z3cform.fieldsets.extensible, line 59, in update Module plone.z3cform.patch, line 30, in GroupForm_update Module z3c.form.group, line 138, in update Module z3c.form.action, line 99, in execute Module z3c.form.button, line 315, in __call__ Module z3c.form.button, line 170, in __call__ Module plone.dexterity.browser.add, line 99, in handleAdd Module z3c.form.form, line 247, in createAndAdd Module plone.dexterity.browser.add, line 78, in add Module plone.dexterity.utils, line 152, in addContentToContainer Module Products.BTreeFolder2.BTreeFolder2, line 455, in _setObject Module zope.event, line 31, in notify Module zope.component.event, line 24, in dispatch Module zope.component._api, line 136, in subscribers Module zope.component.registry, line 321, in subscribers Module zope.interface.adapter, line 585, in subscribers Module zope.component.event, line 32, in objectEventNotify Module zope.component._api, line 136, in subscribers Module zope.component.registry, line 321, in subscribers Module zope.interface.adapter, line 585, in subscribers Module der.freitag.handlers, line 126, in set_customizable_article_link_id Module transaction._manager, line 89, in commit Module transaction._transaction, line 329, in commit Module transaction._transaction, line 443, in _commitResources Module ZODB.Connection, line 567, in commit Module ZODB.Connection, line 623, in _commit Module ZODB.Connection, line 658, in _store_objects Module ZODB.serialize, line 422, in serialize Module ZODB.serialize, line 431, in _dump PicklingError: Can't pickle <class 'plone.directives.form.schema.Schema'>: attribute lookup plone.directives.form.schema.Schema failed ,内容类型只是常规的灵活内容类型。

z3c.relationfield.schema.RelationChoice

编辑:正在创建的对象有一个关系字段(zc.relation),事实证明{{1}}保留了每个成员提供的所有接口的列表任何关系。因此,在从plone.directives.form版本1.0升级到版本1.1之后,无法再解析plone.directives.form上的接口。

z3c.relationfield文档中我看不到更新关系的任何选项,因此唯一的解决方案是获取所有关系并重新创建它们吗?

4 个答案:

答案 0 :(得分:3)

仅供参考,我是如何解决的:

仍然在plone.directives.form 1.0上更新您的对象,以便它们不再提供plone.directives.form.schema.Schema界面。

然后重新创建关系:

from z3c.relationfield import RelationValue
from zc.relation.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.component import getUtility
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent

logger = logging.getLogger(LOGGER)
relations_catalog = getUtility(ICatalog)
intids = getUtility(IIntIds)

relations = [rel for rel in relations_catalog.findRelations()]
len_relations = len(relations)
logger.info('Relations needed to update: {0}'.format(len_relations))

for relation in relations:
    # get the object link and the object linked
    object_with_link = relation.from_object
    object_linked_to = relation.to_object

    # remove the broken relation
    object_with_link.reference = None

    # let the catalog remove the old relation
    notify(ObjectModifiedEvent(object_with_link))

    # create a new relation
    object_linked_to_intid = intids.getId(object_linked_to)
    new_relation = RelationValue(object_linked_to_intid)
    object_with_link.reference = new_relation

    # let the catalog know about this new relation
    notify(ObjectModifiedEvent(object_with_link))

在此之后,停止实例,再次运行buildout以将plone.directives.form更新为1.1版和voilà

答案 1 :(得分:1)

Schema类现在位于plone.supermodel.model中,而不是plone.directives.form.schema。

但是,您应该尝试修复的实际问题是代码是出于某种原因试图在ZODB中存储架构。不支持酸洗/去除Zope接口。

答案 2 :(得分:0)

如果有人遇到这种类型的问题并且无法将旧包裹带回来,这是另一种方法:

import transaction

from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.User import system

from Testing.makerequest import makerequest

from zope.component.hooks import setSite
from zope.globalrequest import setRequest

from zc.relation.interfaces import ICatalog
from z3c.relationfield.event import _relations
from z3c.relationfield.event import _setRelation
from zope.component import getUtility

app = makerequest(app)
newSecurityManager(None, system)
portal = app.Plone
setSite(portal)
portal.REQUEST['PARENTS'] = [portal]
portal.REQUEST.setVirtualRoot('/')
setRequest(portal.REQUEST)

THRESHOLD = 100

relations_catalog = getUtility(ICatalog)

paths = ['/'.join(r.from_object.getPhysicalPath())
         for r in relations_catalog.findRelations() if r.from_object]

relations_catalog.clear()

counter = 0
for path in paths:
    obj = app.unrestrictedTraverse(path)
    for name, relation in _relations(obj):
        _setRelation(obj, name, relation)
    counter += 1
    if counter % THRESHOLD == 0:
        transaction.savepoint()
transaction.commit()

答案 3 :(得分:0)

还有一个选项,我开发了一个名为collective.diversion的软件包,旨在减轻移动类时酸洗错误的痛苦。上述任何一个脚本都不适合我,但是使用collective.diversion。

将包添加到buildout并包含以下ZCML会导致加载项目,并且它们将在写入时保留在正确的位置,因此重新编制目录索引就足够了。

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:diversion="http://namespaces.plone.org/diversion">

  <diversion:class
      old="plone.directives.form.schema.Schema"
      new="plone.supermodel.model.Schema"
      />

</configure>