سؤال

I have a couple of broken objects that I wish to loop through in python script. My use case is as follows: I have renamed my custom product from my.oldproduct to my.newproduct. This has caused the previous objects saved with my.oldproduct to be broken and thus inaccessible. There is a workaround to this as detailed here: Updating broken objects

Now what I want to do is create a python script in the ZMI to loop though all the broken content, change/update them, and thus cause them to be saved using my.newproduct.

I've been unable get the old objects as they are not listed. See a sample of my python script to list all the content in the site, yet they still do not show:

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

How can I get the broken objects from my.oldproduct to be listed?

هل كانت مفيدة؟

المحلول

You'll need to traverse your whole ZODB manually, I'm afraid. If these objects are content objects, you should be able to use the standard OFS methods:

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()

This assumes you already included the work-around you linked to; there is little point in trying to do the above with ZODB.broken.Broken objects.

The above script acts as a bin/instance run script, run it as such:

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

You are going to process everything in the site, a fairly hefty process that will involve a lot of cache churn and possibly a large commit with potential conflicts. You do not want to run this as a through-the-web script, really.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top