SkinScripts instantiating new objects
Hi, I want my SkinScript to instantiate a new object of type ProjektHandler and put it into an attribute called projekt. For this I have created an external method, returning a new object of type ProjektHandler (simplified): def getNewProjektHandler(self, parentId, parentClass): h = ProjektHandler() return h The skinscript look like this: WITH self.getNewProjektHandler(self.id, 'Projektagare') COMPUTE projekt=RESULT This works if I call it from python, e. g print self.mySpecialist.getItem('foo').projekt But it does not work when I call it from the web, e. g http://server/mySpecialist/foo/projekt (see the traceback from the log file below) Has anyone an idea why this doesn't work? Zope 2.3.0b2 ZPatterns 0.4.3b1 /Stefan Karlsson ------ 2001-02-16T11:28:35 PROBLEM(100) ZPatterns Error computing attribute projekt Traceback (innermost last): File /home/stefan/myzope/zope2/lib/python/Products/ZPatterns/AttributeProviders.py, line 311, in _ AttributeFor (Object: GAPMixin) File Products/ZPatterns/Expressions.py, line 122, in eval File DocumentTemplate/DT_Util.py, line 336, in eval (Object: self . getNewProjektHandler ( self . id , 'Projektagare' )) (Info: self) File <string>, line 0, in ? File DocumentTemplate/DT_Util.py, line 140, in careful_getattr AttributeError: getNewProjektHandler
Stefan Karlsson wrote:
Hi,
I want my SkinScript to instantiate a new object of type ProjektHandler and put it into an attribute called projekt.
In your example, there is no sense of the ProjektHandler instance being saved persistently in the attribute. A new object is created for each transaction. Is this what you want?
For this I have created an external method, returning a new object of type ProjektHandler
Where have you put this external method? That is, where in the ZODB?
The skinscript look like this:
WITH self.getNewProjektHandler(self.id, 'Projektagare') COMPUTE projekt=RESULT
This works if I call it from python, e. g print self.mySpecialist.getItem('foo').projekt
But it does not work when I call it from the web, e. g > http://server/mySpecialist/foo/projekt
That's as I expect. Generally, you call methods from URLs, you don't retrieve the values of attributes. -- Steve Alexander Software Engineer Cat-Box limited http://www.cat-box.net
At 14:31 2001-02-16, Steve Alexander wrote:
Stefan Karlsson wrote:
Hi,
I want my SkinScript to instantiate a new object of type ProjektHandler and put it into an attribute called projekt.
In your example, there is no sense of the ProjektHandler instance being saved persistently in the attribute. A new object is created for each transaction. Is this what you want?
Yes, that was my intention. BTW is it possible to save the ProjektHandler instance persistently in the attribute? Is there an easier way than creating a separate specialist for the ProjektHandler class and storing the instances there?
For this I have created an external method, returning a new object of type ProjektHandler
Where have you put this external method? That is, where in the ZODB?
I have put it in the rack, the specialist and higher up in the hierarchy. Makes no difference.
The skinscript look like this:
WITH self.getNewProjektHandler(self.id, 'Projektagare') COMPUTE projekt=RESULT
This works if I call it from python, e. g print self.mySpecialist.getItem('foo').projekt
But it does not work when I call it from the web, e. g > http://server/mySpecialist/foo/projekt
That's as I expect. Generally, you call methods from URLs, you don't retrieve the values of attributes.
So, what do you suggest, should I implement __bobo_traverse__ or something in foo to make the URL work? /Stefan Karlsson
Stefan Karlsson wrote:
BTW is it possible to save the ProjektHandler instance persistently in the attribute? Is there an easier way than creating a separate specialist for the ProjektHandler class and storing the instances there?
I think you're getting design and implementation confused here. Should ProjektHandlers be a Dataskins? If so, they should live in their own Rack. Or, does a ProjectHandler really belong as a part of the instance of something else? In this latter case, you could add a ProjectHandler as an attribute. As to whether this is a wise thing to do; well, I can't say, as I don't know what problem you're trying to solve. If you want to store ProjektHandlers as attributes of a persistent class, just add them, using a method of your base Python class, or an External Method. In this case, you'll almost certainly want to define the ProjektHandler class in a Product, and not in an External Method.
That's as I expect. Generally, you call methods from URLs, you don't retrieve the values of attributes.
So, what do you suggest, should I implement __bobo_traverse__ or something in foo to make the URL work?
Yes. For example, make projekt a method rather than an attribute. Or, have a getProjekt method. I'd like to offer some advice, but please don't take this the wrong way; I mean it respectfully. You seem to be trying to design your application using SkinScript and External Methods and Specialists. I suggest first designing the application on paper, then implementing it using SkinScript, Specialists and so forth. -- Steve Alexander Software Engineer Cat-Box limited http://www.cat-box.net
At 16:21 2001-02-16, Steve Alexander wrote:
Stefan Karlsson wrote:
BTW is it possible to save the ProjektHandler instance persistently in the attribute? Is there an easier way than creating a separate specialist for the ProjektHandler class and storing the instances there?
I think you're getting design and implementation confused here.
Should ProjektHandlers be a Dataskins? If so, they should live in their own Rack. Or, does a ProjectHandler really belong as a part of the instance of something else? In this latter case, you could add a ProjectHandler as an attribute. As to whether this is a wise thing to do; well, I can't say, as I don't know what problem you're trying to solve.
I have found a workaround for the 'Error computing attribute' problem by instantiating the ProjektHandler object directly in __bobo_traverse__: def __bobo_traverse__(self, REQUEST, name): if name=='projekt': return self.getNewProjektHandler(self,id, 'Projektagare').__of__(self) else: return getattr(self, name) For those of you that are interested in a long explanation of how I designed the system, read on... A ProjektHandler is a ZPHandler that is a "virtual folder" that looks like a normal Zope folder but doesn't store any objects in itself. Instead the storage is delegated to ZPatterns. There is also an OMHandler class that implements the same interface as ZPHandler but stores the objects in itself like ObjectManager, but that's another story. In each class that has an aggregate to another class I instantiate a handler for that other class. As an example, look at the UML class diagram below. We can see that both A and C has an aggregate to class B, that is, a one-to-many relationship. A also has an aggregate to D. X=diamond=aggregate +-----+ * +-----+ ! A !X----! D ! +-----+ +-----+ X ! ! * +-----+ ! B ! +-----+ ! * ! X +-----+ ! C ! +-----+ So what we need is a handler class that manages objects of class B, so we create a BHandler by simply subclassing ZPHandler and telling it what objects to handle. One BHandler instance is put into A and another is put into C. Both instances are called 'bs'. We also need a DHandler that is put into A. The nice thing is that it is very easy to get management tabs for B:s and D:s in A and B:s in C in the management interface. Another nice thing is that B instances actually seems to exist in multiple parents! And all objects seems to exist as normal Zope objects even if the are stored in SQL database. Now instantiate objects of type A, B and C and call them a1, b1, c1. From python we can write a1.bs.getItem('b1) to get the b1 object. We can of course also write c1.bs.getItem('b1') and get the same object. The handler attribute bs is instantiated by a ZPatterns skinscript as a new object when they are first accessed in every transaction Now wouldn't it be nice to access this URL: http:/server/path/to/a1/bs/manage_workspace to get the management interface for the B objects belonging to A? But here comes the problem! This doesn't work for me. I get the 'Error computing attribute' in ZPatterns. I have also tried calling self.a.bs.getItem('b1') in __bobo_traverse__ but get the same error. As I said I have found a workaround but I suspect it's a bug in ZPatterns... Anyway, this was the way I designed this system and it would be nice to have some comments. Thanks Steve for your help! /Stefan Karlsson Everynet Consulting
participants (2)
-
Stefan Karlsson -
Steve Alexander