2013-04-11 110 views
1

我有一对破损的对象,我希望在python脚本中循环。我的用例如下:我已将我的自定义产品从my.oldproduct更名为my.newproduct。这导致与my.oldproduct保存的以前的对象被破坏,因此无法访问。这里有一个解决方法,详细在这里:Updating broken objects在Plone中循环浏览破碎的对象

现在我想要做的是在ZMI中创建一个python脚本来循环所有破碎的内容,更改/更新它们,从而使它们保存使用my.newproduct。

我一直无法获得旧对象,因为它们没有列出。见我的Python脚本样本列出站点中的所有内容,但他们仍然没有显示:

from Products.CMFCore.utils import getToolByName 

app = context.restrictedTraverse('/') 
sm = app.plone.getSiteManager() 

catalog = getToolByName(context, 'portal_catalog') 
results = catalog.searchResults() 

count = 0 
for obj in results: 
    print obj.meta_type 
    count += 1 

print str("Found " + str(count) + " matching objects") 

return printed 

如何我可以从my.oldproduct破碎的物体被上市?

回答

4

恐怕你需要手动遍历整个ZODB。如果这些对象是内容对象,你应该能够使用标准的OFS方法:

from collections import deque 
from datetime import datetime 

import transaction 
from zope.app.component.hooks import setSite 
from Testing.makerequest import makerequest 
from AccessControl.SecurityManagement import newSecurityManager 

from my.newproduct.types import ArchetypesContentType 


site_id = 'Plone'  # adjust to match your Plone site object id. 
admin_user = 'admin' # usually 'admin', probably won't need adjusting 
app = makerequest(app) 
site = app[site_id] 
setSite(site) 
user = app.acl_users.getUser(admin_user).__of__(site.acl_users) 
newSecurityManager(None, user) 


def treeWalker(root): 
    # stack holds (parent, id, obj) tuples 
    stack = deque([(None, None, root)]) 
    while stack: 
     parent, id, next = stack.popleft() 
     try: 
      stack.extend((next, id, child) for id, child in next.objectItems()) 
     except AttributeError: 
      # No objectItems method 
      pass 
     yield parent, id, next 


count = 0 
for parent, id, obj in treeWalker(site): 
    if isinstance(obj, ArchetypesContentType): 
     print 'Found content type object {} at {}'.format(id, '/'.join(object.getPhysicalPath())) 
     obj._p_changed = True # mark it as changed, force a commit 
     count += 1 
     if count % 100 == 0: 
      # flush changes so far to disk to minimize memory usage 
      transaction.savepoint(True) 
      print '{} - Processed {} items'.format(datetime.now(), count) 

transaction.commit() 

这里假设你已经包括的工作,你周围挂;尝试使用ZODB.broken.Broken对象进行上述操作没有意义。

上述脚本作为一个bin/instance run脚本,运行它,例如:

bin/instance run path/to/this/script.py 

你要处理一切在现场,一个相当沉重的过程,会涉及大量的缓存流失和可能是一个潜在的冲突巨大的承诺。真的,您不希望将其作为通过网络脚本运行。

+0

感谢Martijn,但由于权限不足,我无法将此代码作为ZMI中的python脚本执行。 (RestrictedPython)。我发现将它添加到我的产品的文件系统以允许执行上述操作是很奇怪的,因为它是一次性任务。 – Frankline 2013-04-12 05:16:39

+1

@Frankline:充实了一些;你*真的*不想通过网络来运行这个。这是可能的(用'.pop(0)'替换''deque'而不是'.popleft()',而不用'transaction.commit()'和'print'语句),我只是不要我认为这不是一个好主意。 – 2013-04-12 08:36:21