RE: [Zope] Re: creating ZClasses with external method
Alex> I still cannot create ZClasses with an external method (using Alex> aquisition) Since I can do it with ZPublisher.Client and by typing Alex> in a URL into my browser, but not via an external method, this is Alex> really seeming like a bug. Should I report this to Collector? <snip>
It looks so easy in retrospect :-) This method below works a like a charm. I adapted this from Brian Lloyd's post today to zope-dev (subject: ZClasses instances become detached from class).
def addFoo(self, id='a_obj', REQUEST=None): """ """ # Get the actual destination object, using the this() # method, to be sure we get it in the right context.. self=self.this()
# Create the new instance newob=self.Control_Panel.Products.Foo.foo(id) # redundant? newob.id=id
# Set properties based on the contents of the Add form newob.propertysheets.info.manage_changeProperties(REQUEST)
# Add the new instance to the target object self._setObject(id, newob)
return 'OK!'
Question: why the heck does one need to call self=self.this()? In what cases does it make a difference? That's just weird. Is this() def'd in SimpleItem.py?
Alex Rice
Well, using the this() method is necessary because of the behind-the-scenes trickery that is actually going on when you create a new object. If you look at the target URL when you create an object, it looks something like: /myFolder/manage_addProduct/OFSP/folderAdd The 'manage_addProduct' method of ObjectManagers is actually a FactoryDispatcher object that masquerades as a method. It implements the trickery to find the right product and constructor, etc. The upshot is that when you actually submit the add form for an object, it is submitted to a constructor that is several levels deeper in the URL hierarchy than the actual destination where you are creating the new object. It is going through the destination object, a factory dispatcher, and the factory for the object itself to get to the object constructor. The constructor, of course, often wants to use the 'self' object, and expects it to be the parent object that the new object will be living in. However, as you can see above, the 'self' that you see in your external method is very likely going to actually be the _Factory_ object (which actually contains the constructor). Because of that, you need to set 'self' to the actual destination where the object will be living - we used to call self.Destination() to get that object, but the this() method has been made an alias for the old Destination() method. Using "self=self.this()" in your external method will set 'self' to the actual destination object. While this may be kind of unintuitive, it is a necessary evil that you have to set the destination to the right thing yourself, because your constructor may want to use attributes of the Product itself. For example, above, you created your ZClass above with the line: # Create the new instance newob=self.Control_Panel.Products.Foo.foo(id) It would be better in this case (to avoid hard coding product names and locations) to use 'self' in its initial context (the factory), and defer setting self to this() until after you are done using attributes of the Product/ Factory: def addFoo(self, id='a_obj', REQUEST=None): """ """ # Create the new instance. Here, self is still # the Factory, which can acquire the ZClass that # we want to instantiate (foo) from the Product. newob=self.foo(id) # Now we're done using things from the Factory or # Product, so set self to the actual destination # object where our new instance will live. self=self.this() # Set properties based on the contents of the Add form newob.propertysheets.info.manage_changeProperties(REQUEST) # Add the new instance to the destination object (which # is self at this point). self._setObject(id, newob) return 'OK!' The gory details of how this stuff works can be found in the App package in Zope (Product, Factory, FactoryDispatcher, etc.) Hopefully this explanation helps a bit - let me know if it did more harm than good, and maybe I can get Jim to explain it better... :^) Brian Lloyd brian@digicool.com Software Engineer 540.371.6909 Digital Creations http://www.digicool.com
On Tue, 13 Jul 1999 09:53:00 -0400, Brian Lloyd <Brian@digicool.com> said: <snip> Brian> # Create the new instance Brian> newob=self.Control_Panel.Products.Foo.foo(id) Brian> It would be better in this case (to avoid hard coding Brian> product names and locations) to use 'self' in its initial Brian> context (the factory), and defer setting self to this() Brian> until after you are done using attributes of the Product/ Brian> Factory: Brian> # Create the new instance. Here, self is still Brian> # the Factory, which can acquire the ZClass that Brian> # we want to instantiate (foo) from the Product. Brian> newob=self.foo(id) <snip> Makes sense, but when I try newob=self.foo(id), I get an AttributeError on 'foo'. (I'm working on an external method which is totally outside the ZClass's Product, it just has to create a ZClass as a side effect). Brian> The gory details of how this stuff works can be found in Brian> the App package in Zope (Product, Factory, FactoryDispatcher, Brian> etc.) Hopefully this explanation helps a bit - let me know Brian> if it did more harm than good, and maybe I can get Jim to Brian> explain it better... :^) Yes, this does help out. I shall take a look at the App package. Thanks, Alex Rice | alrice@swcp.com | http://www.swcp.com/~alrice Current Location: N. Rio Grande Bioregion, Southwestern USA
participants (2)
-
Alex Rice -
Brian Lloyd