2013-04-11 37 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