[Zope3-Users] Re: Evolution of ZoDB after changing python modules
structure (moving content classes to another module)
Rupert Redington
rupert at neontribe.co.uk
Tue Jun 12 06:59:01 EDT 2007
Aleksander Kowalczyk wrote:
> On 6/8/07, Alek Kowalczyk <thealx at poczta.onet.pl> wrote:
>>
>> Alek Kowalczyk <thealx at ...> writes:
>>
>> >
>> > Hi,
>> > I moved my content class from mypackage.mymodule.MyContentClass into
>> > mypackage.mysubpackage.mymodule.MyContentClass.
>> > But when started Zope and went to visit an object I have previously
>> created (of
>> > MyContentClass), I get:
>> > ComponentLookupError: ((<persistent broken
>> mypackage.mymodule.MyContentClass
>> > instance '\x00\x00\x00\x00\x00\x00\x02q'>,
>> > <zope.publisher.browser.BrowserRequest instance
>>
> I found a quite well working solution on
>> http://mail.zope.org/pipermail/zodb-dev/2006-September/010382.html
>>
>> There was only one issue: this solution assumes that we have given a DB,
>> while
>> Zope evolve method receives already open connection. Unfortunately
>> classFactory
>> from DB is cached in Connection's private fields in constructor.
>> Because of that I could not assign my custom 'renaming' class factory
>> using:
>>
>> def evolve(context): #won't work!
>> context.connection.db().classFactory = myClassFactory
>>
>> Instead I had to do some dirty private fields substitution in
>> Connection's
>> ObjectReader:
>>
>> def evolve(context): #this works nice
>> context.connection._reader._factory = myClassFactory
>
>
> I shouldn't announce success too early. The solution works but only during
> first Zope run (i.e just after evolving the schema).
> Although classFactory returns proper class during evolve, the new class
> name
> is not saved in ZoDB, so after next unghosting object get old class names
> again.
>
> Here is my evolve script. I really don't know what more should I do to make
> Zope/ZoDB write the new class name in ZoDB. Can someone help me a bit... :)
> ?
>
> def convertingClassFactory(connection, moduleName, globalName):
> #convert class name to new one and return the class object
>
> def evolve(context):
> #dirty hack to substitute classFactory
> context.connection._reader._factory = convertingClassFactory
> root = context.connection.root().get(ZopePublication.root_name, None)
> for object in findObjectsMatching(root, lambda x: True):
> if hasattr(object, '_p_activate'):
> object._p_activate()
> object._p_changed = True
>
Somebody correct me if I'm wrong
I imagine you'd need to commit the transaction manually:
def evolve(context):
#dirty hack to substitute classFactory
context.connection._reader._factory = convertingClassFactory
root = context.connection.root().get(ZopePublication.root_name, None)
for object in findObjectsMatching(root, lambda x: True):
if hasattr(object, '_p_activate'):
object._p_activate()
object._p_changed = True
import transaction
transaction.commit()
Hope that helps,
Rupert
More information about the Zope3-users
mailing list