Calling dtml method from PythonScript, _.None, _ ?
I'm trying to eliminate query strings on my DHTML methods, to convert http://myhost.com/Products?productid=xyz into http://myhost.com/ProcessPath/xyz/ProductInfo.htm I've created a Python Script (2.3.2) that looks like this: --- target = traverse_subpath[-1] if target == 'ProductInfo.htm': container.Products(context,productid=traverse_subpath[0]) --- Also other variations of the function call, none work. basically I'm getting a KeyError in <standard_html_header> (called from Products) on 'bgcolor' where standard_html_header has <dtml-unless bgcolor> ... </dtml-unless> This code works when not passing through a Python Script call. What is the correct way to emulate a <dtml-var> call from a Python Script? Any idea why the dtml-unless fails when called indirectly through a python script? --- I know about the PathHandler product, but that doesn't quite fit my needs, my Python Script will be more complicated once I get this working. Brad Clements, bkc@murkworks.com (315)268-1000 http://www.murkworks.com (315)268-9812 Fax netmeeting: ils://ils.murkworks.com AOL-IM: BKClements
Brad Clements wrote:
I'm trying to eliminate query strings on my DHTML methods, to convert
http://myhost.com/Products?productid=xyz
into
http://myhost.com/ProcessPath/xyz/ProductInfo.htm
I've created a Python Script (2.3.2) that looks like this:
--- target = traverse_subpath[-1] if target == 'ProductInfo.htm': container.Products(context,productid=traverse_subpath[0])
---
You might try: container.Products(container.Products, productid=traverse_subpath[0]) The first parameter of a DTML object call is the "client". If you pass the object itself as the client this generally works. Keep in mind that you are now passing your URL arguments as keywords rather than through REQUEST. This makes a big difference in where they show up in the namespace (at the top rather than the bottom), and ZSQL methods will not see them without explicitly passing them along. -- | Casey Duncan | Kaivo, Inc. | cduncan@kaivo.com `------------------>
From: "Brad Clements" <bkc@murkworks.com>
target = traverse_subpath[-1] if target == 'ProductInfo.htm': container.Products(context,productid=traverse_subpath[0])
In this case, you probably want to use: container.Products(container.Products, context.REQUEST, productid=traverse_subpath[0]) ..or.. req = context.REQUEST req.set('productid', traverse_subpath[0]) container.Products(context, req) Lecture time: DTML Methods have the call signature: (client=None, REQUEST={}, RESPONSE=None, **kw) When a Method is the target of a URL, ZPublisher calls it like this: method(context, REQUEST, RESPONSE) The Method creates a namespace and pushes some standard shared data onto it, followed by the REQUEST and the context object (the object on which the method is being called). RESPONSE is just used to set up headers properly, and can be ignored; You shouldn't pass it yourself. Now the context is on top of the namespace, so the Method has access to its attributes (including acquired ones). If a name is not found in the context, the REQUEST is searched next. When DTML calls a DTML Method using <dtml-var method>, it does so like this: method(None, _) The trick, here, is that the namespace "_" already contains the client, request, and keyword arguments that were passed to the *calling* DTML Method. The called Method notices that it has been given a valid namespace, and adopts it. There is no client, and no keyword arguments, so nothing else gets pushed onto the namespace. The called method has access to the exact same set of names as the caller did when it performed the call. When you call a DTML Method from Python, whether it be filesystem code, a Script, or an expression in DTML or a Page Template, you must decide what information to make available to it. If you have access to a properly constructed namespace (it was passed to you, or bound by your Script) you can simply pass it along: method(None, namespace) Otherwise, you will probably want to call it like ZPublisher does, passing a client and the REQUEST. A reasonable client to choose is the object from which you are acquiring the method (assuming that you haven't simply been handed the method), and you can probably acquire the REQUEST from it as well (or from your container). This gives you: container.Products(container.Products, context.REQUEST) If you want to pass additional data, you have two choices. You can use keyword arguments, in which case you might override names in the client or REQUEST. Second, you can add the data to the REQUEST using set(), in which case it might be hidden by names in the client or REQUEST. Cheers, Evan @ digicool & 4-am
Thank for the detailed explanation. Adding REQUEST solved my problem. I had also tried adding _ but that didn't work from pythonscript even though _ was bound to the dtml namespace. (ie, I tried context.ProductInfo(None,_,productid=traverse_path[0]) But I still think there is a problem. pythonscript ProcessPath calls DTML Method ProductInfo which dtml-var DTML Method Standard_Html_Header. In Standard_Html_header I have <dtml-unless bgcolor> do something </dtml-unless> My understanding of dtml-unless is that it's true if bgcolor is None, '' or does not exist in the namespace. If ProcessPath includes REQUEST in it's call to ProductInfo, all is well. But if REQUEST is not included, then I get a KeyError on the <dtml-unless bgcolor> statement. This doesn't seem correct. I'd expect to not get a KeyError, since dtml-unless is supposed to catch that. Isn't it? So .. if a DTML_Method does not get REQUEST, looks like <dtml-unless> doesn't do what's expected. Brad Clements, bkc@murkworks.com (315)268-1000 http://www.murkworks.com (315)268-9812 Fax netmeeting: ils://ils.murkworks.com AOL-IM: BKClements
From: "Brad Clements" <bkc@murkworks.com>
Adding REQUEST solved my problem. I had also tried adding _ but that didn't work from pythonscript even though _ was bound to the dtml namespace.
That's probably because your Script wasn't being called from DTML, and therefore had an empty namespace.
pythonscript ProcessPath calls DTML Method ProductInfo which dtml-var DTML Method Standard_Html_Header.
If ProcessPath includes REQUEST in it's call to ProductInfo, all is well. But if REQUEST is not included, then I get a KeyError on the <dtml-unless bgcolor> statement.
Hmm. I'm not sure why that is. I'll have to look into it. Cheers, Evan @ digicool & 4-am
participants (3)
-
Brad Clements -
Casey Duncan -
Evan Simpson