Hello All: Do any of you have an idea about how to solve the followong problem: I am working on creating a zope product that uses multiple DTML pages to gather information from the user before actually constructing the product class, sort of like a 'wizard' interface. I am pretty new to this, so please bear with me. The idea is that __init__.py exposes the appropriate DTML form for step 1 in the process, as well as the relevant module level function, e.g., def initialize(context): context.registerClass(module.class, permission="Add class_name", constructors=(module.Step1Form, module.Step1Func)) Step1Func would then return another DTML page/form called Step2Form Step2Form gets more info from the user and calls Step2Func Step2Func processes the returned info and in turn returns StepFinalForm StepFinalForm calls StepFinalFunc which actually instantiates the class and does self._setObject and all of that good stuff. Using this approach, I get through Step1Form and Step1Func OK, but when Step1Func attempts to return Step2Form, it appears to have no acquisition context and returns KeyErrors like: Error Type: KeyError Error Value: standard_html_header . . .or AttributeErrors like: Error Type: AttributeError Error Value: aq_parent For example: #This is a module to create an object in steps from OFS.SimpleItem import SimpleItem from Globals import DTMLFile Step1Form = DTMLFile("dtml/Step1Form", globals()) Step2Form = DTMLFile("dtml/Step2Form", globals()) StepFinalForm = DTMLFile("dtml/StepFinalForm", globals()) def Step1Func(self, REQUEST): """This is the doc string""" request = REQUEST . . .more code in here. . . return Step2Form(self, request) def Step2Func(self, REQUEST): """This is the doc string""" request = REQUEST . . .yet more code. . . return StepFinalForm(self, request) def StepFinalFunc(self, REQUEST): """This is the doc string""" request = REQUEST . . .and yet more code. . newClass=someClass(id, title, moreArgs) self._setObject(id, newClass) return self.manage_main(self, request) To make a long story even longer. . .is there a way to wrap a returned DTML document in an intact acquisition context? I've tried .__of__(self) tacked on to the return statement but it seems as if it is the 'self' object that lacks an acquisition context. I've also tried making the DTML an attribute of a class that inherits from SimpleItem, which gives the KeyError on standard_html_header (incidentally, none of the DTML includes references to standard_html_anything). If anyone knows of a product that uses a multi-step construction process prior to instantiation and ZODB storage I'd love to see how it works. Thanks for any thoughts. Richard
----- Original Message ----- From: "Richard Rosenberg" <richrosenberg@earthlink.net>
I am working on creating a zope product that uses multiple DTML pages to gather information from the user before actually constructing the product class, sort of like a 'wizard' interface. I am pretty new to this, so please bear with me.
To make a long story even longer. . .is there a way to wrap a returned DTML document in an intact acquisition context? I've tried .__of__(self) tacked on to the return statement but it seems as if it is the 'self' object that lacks an acquisition context. I've also tried making the DTML an attribute of a class that inherits from SimpleItem, which gives the KeyError on standard_html_header (incidentally, none of the DTML includes references to standard_html_anything).
If anyone knows of a product that uses a multi-step construction process prior to instantiation and ZODB storage I'd love to see how it works.
Your process seems a bit convoluted. Perhaps if you post what you are trying to accomplish someone may be able to assist (do you really want end-users to create new classes? or is there some other objective?)
Jonathan: Thanks for your advice. . .I'll try and be more concise. Allow me to start off by saying I have just finished going through the Zope Bible, and this is purely an educational exercise. This particular product class will (in the end I hope) essentially be a sort of query template that relies on zSQL methods. It began as an experiment to determine if I could get by with only 2 zSQL methods to serve all queries (except DELETEs, which at the moment I am not interested in) sent to a database connection. Before anyone gets upset, please keep in mind that this is an experimental effort only at this point. At the moment I have 2 (rather lengthy) zSQL methods - one for SELECTs and one for UPDATEs/INSERTs - that properly handle most types of joins, and support just about any WHERE clause. Each zSQL method expects one argument, which is a list of dictionaries (for SELECTs a list containing one dictionary). The dictionaries which comprise the query parameter are constructed via 3 python scripts and 3 DTML documents. Each of the DTML documents gathers information from the user and each script is called when the rendered DTML from is submitted: DTML 1 asks for a database connection ID from a dropdown list, and on submit calls a script that retrieves a listing of all of the available tables via one of the aforementioned zSQL methods. The same script then returns DTML 2. . . DTML 2 displays a listing of tables from which the user must select one or more table names. DTML 2 then calls another script that retrieves a listing of all available field names for each table, along with type information for each field. The same script then returns DTML 3. . . DTML 3 allows the user to define join criteria if applicable, fields to include in the result, and any selection criteria (sql WHERE clause). On submit DTML 3 then calls yet another script which uses all of the gathered information thus far to construct and validate the parameter sent to the existing zSQL method. A final DTML page is returned to display the results for testing purposes. So I thought. . .would it even be possible to make this into a product? I realize that it may not be desirable, but is it possible? Presently, when I select the product from the product add list, the first step (selecting a connection id on a DTML document) goes fine, and it calls a module level level function to retrieve the listing of tables. The function chokes when it attempts to return another DTML document on the following line: return Step2Form(self, request) which is why I ask the question: How does one create a product which relies on multiple pages to gather information from the user when the product instance is added to a folder via the product add list (a wizard-like interface)? Can it be done, or is this a limitation of Zope? In messing around with this I have found precious little information related to this specific question, and I am aware of no products which implement this functionality in their 'product add' process. In fact, it seems to be conspicuously absent. Thanks. Richard On 09/22/2004 07:59:47 PM, Jonathan Hobbs wrote:
----- Original Message -----
I am working on creating a zope product that uses multiple DTML pages to gather information from the user before actually constructing the product class, sort of like a 'wizard' interface. I am pretty new to this, so please bear with me.
To make a long story even longer. . .is there a way to wrap a returned DTML document in an intact acquisition context? I've tried .__of__(self) tacked on to the return statement but it seems as if it is the 'self' object that lacks an acquisition context. I've also tried making the DTML an attribute of a class that inherits from SimpleItem, which gives the KeyError on standard_html_header (incidentally, none of the DTML includes references to standard_html_anything).
If anyone knows of a product that uses a multi-step construction process prior to instantiation and ZODB storage I'd love to see how it works.
Your process seems a bit convoluted. Perhaps if you post what you are trying to accomplish someone may be able to assist (do you really want end-users to create new classes? or is there some other objective?)
From: "Richard Rosenberg" <richrosenberg@earthlink.net>
Allow me to start off by saying I have just finished going through the Zope Bible, and this is purely an educational exercise. This particular product class will (in the end I hope) essentially be a sort of query template that relies on zSQL methods. It began as an experiment to determine if I could get by with only 2 zSQL methods to serve all queries (except DELETEs, which at the moment I am not interested in) sent to a database connection. Before anyone gets upset, please keep in mind that this is an experimental effort only at this point.
At the moment I have 2 (rather lengthy) zSQL methods - one for SELECTs and one for UPDATEs/INSERTs - that properly handle most types of joins, and support just about any WHERE clause. Each zSQL method expects one argument, which is a list of dictionaries (for SELECTs a list containing one dictionary). The dictionaries which comprise the query parameter are constructed via 3 python scripts and 3 DTML documents. Each of the DTML documents gathers information from the user and each script is called when the rendered DTML from is submitted:
DTML 1 asks for a database connection ID from a dropdown list, and on submit calls a script that retrieves a listing of all of the available tables via one of the aforementioned zSQL methods. The same script then returns DTML 2. . .
DTML 2 displays a listing of tables from which the user must select one or more table names. DTML 2 then calls another script that retrieves a listing of all available field names for each table, along with type information for each field. The same script then returns DTML 3. . .
DTML 3 allows the user to define join criteria if applicable, fields to include in the result, and any selection criteria (sql WHERE clause). On submit DTML 3 then calls yet another script which uses all of the gathered information thus far to construct and validate the parameter sent to the existing zSQL method. A final DTML page is returned to display the results for testing purposes.
So I thought. . .would it even be possible to make this into a product? I realize that it may not be desirable, but is it possible?
Presently, when I select the product from the product add list, the first step (selecting a connection id on a DTML document) goes fine, and it calls a module level level function to retrieve the listing of tables. The function chokes when it attempts to return another DTML document on the following line:
return Step2Form(self, request)
which is why I ask the question:
How does one create a product which relies on multiple pages to gather information from the user when the product instance is added to a folder via the product add list (a wizard-like interface)? Can it be done, or is this a limitation of Zope?
In messing around with this I have found precious little information related to this specific question, and I am aware of no products which implement this functionality in their 'product add' process. In fact, it seems to be conspicuously absent. Thanks.
There may be some hints in a couple of Dieter's packages: http://www.dieter.handshake.de/pyprojects/zope/Wizzard.html http://www.dieter.handshake.de/pyprojects/zope/Dispatcher.html Jonathan
Richard Rosenberg wrote at 2004-9-22 23:07 +0000:
... I am working on creating a zope product that uses multiple DTML pages to gather information from the user before actually constructing the product class, sort of like a 'wizard' interface. I am pretty new to this, so please bear with me.
The idea is that __init__.py exposes the appropriate DTML form for step 1 in the process, as well as the relevant module level function, e.g.,
def initialize(context): context.registerClass(module.class, permission="Add class_name", constructors=(module.Step1Form, module.Step1Func))
Step1Func would then return another DTML page/form called Step2Form
Step2Form gets more info from the user and calls Step2Func
Step2Func processes the returned info and in turn returns StepFinalForm StepFinalForm calls StepFinalFunc which actually instantiates the class and does self._setObject and all of that good stuff.
You must declare all your "Step<i>{Form|Func}" as constructors (like you did for "i==1"). This declarations makes them available via the "product context" (where you are when you are creating a new object in the standard way). -- Dieter
Thanks Dieter. . . I've decided on a different approach, and now I am truly baffled. It seems like there is something incredibly obvious that I am not getting about how acquisition works. I've looked at the Dev Guide so much I see it in my sleep, but I am not getting it. I am now creating a class that has among other things) zSQL methods as attributes. That part works fine. Next I thought I'd also make my life easier (hah!) by using some functionality that seems to be built in to the sql DAs (gadfly, postgresql) themselves, namely the tables() method. Like so: class zBusView(SimpleItem): """A Business View Object""" meta_type = "zBusView" def __init__(self, id, title, connectionID): self.id = id self.title = title self.connectionID = cID = connectionID gf = 'GetFields' sql="""select * from <dtml-var tablename> where 1=0""" setattr(self, gf, SQL(gf, '', cID, 'tablename', sql)) conn = getattr(self, cID) setattr(self, 'GetTables', conn.tables) I initially thought the getattr() call would resolve upward in the object hierarchy, but as you probably know, it is only looking inside the attributes of the class. Is there any way to do this? Do I need to inherit from another class or two? Later I would like to put that getattr() in a separate class method that resolves the reference in real time, but I'm trying it here first. What is most puzzling to me is that the first setattr creating the zsql method resolves to a database connection without difficulty, but the getattr() fails. Thanks very much for your help thus far. Truly vexed, Richard On 09/24/2004 12:14:26 PM, Dieter Maurer wrote:
Richard Rosenberg wrote at 2004-9-22 23:07 +0000:
... I am working on creating a zope product that uses multiple DTML pages
to gather information from the user before actually constructing the
product class, sort of like a 'wizard' interface. I am pretty new to
this, so please bear with me.
The idea is that __init__.py exposes the appropriate DTML form for step 1 in the process, as well as the relevant module level function, e.g.,
def initialize(context): context.registerClass(module.class, permission="Add class_name", constructors=(module.Step1Form, module.Step1Func))
Step1Func would then return another DTML page/form called Step2Form
Step2Form gets more info from the user and calls Step2Func
Step2Func processes the returned info and in turn returns StepFinalForm StepFinalForm calls StepFinalFunc which actually instantiates the class and does self._setObject and all of that good stuff.
You must declare all your "Step<i>{Form|Func}" as constructors (like you did for "i==1"). This declarations makes them available via the "product context" (where you are when you are creating a new object in the standard way).
-- Dieter
Thanks again Dieter. . . Shortly after sending that last message I see the error of my ways. . .I have moved the relevant operations out of __init__ and now they work (sort of). I guess it is important to know precisely where you are at the moment when it comes to Zope acquisition. . .duh. Now it's off to the races (the turtle races anyway) and I'll post how this turns out along with some comments later. I'm presently accessing the methods of a zpsycopg DA to retrieve the table names contained in the underlying database. . .woohoo. If most of the DAs are similar in their structure, the rest should be relatively easy. R
Richard Rosenberg wrote at 2004-9-24 22:21 +0000:
... class zBusView(SimpleItem): """A Business View Object""" meta_type = "zBusView" def __init__(self, id, title, connectionID): ... conn = getattr(self, cID) ... I initially thought the getattr() call would resolve upward in the object hierarchy,
It does indeed, but in "__init__" a new object is constructed. Therefore, this new object is not yet in the object hierarchy... -- Dieter
participants (3)
-
Dieter Maurer -
Jonathan Hobbs -
Richard Rosenberg