DTML<->Python confusion (RE: [Zope] How to make a script return rendered dtml)
I've spent hours, maybe days, being confused about this as well. According to the Zope API documentation and ZDP at http://zdp.zope.org/projects/zfaq/faq/DTML/959888072 http://zdp.zope.org/projects/zsnippet/snippets/DTMLTags/CallingDTMLMetho ds someDTMLMethod(_.None, _) should work. Because of the unclear/complex calling conventions and integration between DTML and Python I've had to keep some code in DTML. Other related questions are: How do you do dtml-with and dtml-let in a Python script? (I.e. put something on the namespace) How do you give positional (not keyword) arguments to a DTML method; is there any difference? When is __call__ called, when is __str__ called, and when is index_html called? Other basic functions worth knowing about for a class/object to be a good-behaving Zope object? When does RESPONSE need to be passed; it can always be gotten from the REQUEST, right? Calling a DTML method, when to use client and when to use REQUEST? Is calling with client and REQUEST the same as adding client to the namespace (REQUEST) and calling it with an client=None? Are namespace, _, REQUEST, and context just different names for the same thing? I've been dreaming about a FAQ answering all of this (and a bunch of ZClasses questions I have). Me thinks the ZDP should be integrated with Zope.org, and all Zope.org members given access to add FAQs (I am not allowed to add FAQs now). Ideally, somebody should be adding FAQs all the time, and the FAQ index should be posted regularly to zope-dev... Btw, I think http://zdp.zope.org/projects/zfaq/faq/DTML/959888072 gets the order of aMappingObject and aClient wrong in the first code line. Bye, -- Bjorn -----Original Message----- From: Tim Hicks [mailto:tim@sitefusion.co.uk] Posted At: Thursday, June 14, 2001 00:15 Posted To: Zope List Conversation: [Zope] How to make a script return rendered dtml Subject: Re: [Zope] How to make a script return rendered dtml ----- Original Message ----- From: "Eric Balasbas" <ebalasba@bway.net> To: "Tim Hicks" <tim@sitefusion.co.uk> Cc: <zope@zope.org> Sent: Wednesday, June 13, 2001 4:33 PM Subject: Re: [Zope] How to make a script return rendered dtml
I'm not sure if this is the best way to do it, but if you want to render a DTML method or DTML document inside a Python script, use the syntax:
someDTMLMethod(_.None, _)
I tried this: print context(_.None, _) and got this error: Error Type: NameError Error Value: _ So I tried context.id(_.None,_) and got the same. So I tried 'print context(None,_)', with the same error resulting. Finally, I have tried: print context(None,) and got Error Type: KeyError Error Value: standard_html_header This last error at least seems like it's on the right track as it is parsing through the text of the file. What's going wrong, any idea? thanks tim
Eric Balasbas Senior Developer eric@virtosi.com
http://www.virtosi.com/ Virtosi Ltd. Design -- Branding -- Zope
On Wed, 13 Jun 2001, Tim Hicks wrote:
I have a ZClass (testclass) which subclasses DTMLDocument, and within this zclass, I have a script (python) called index_html. Obviously, this script is called each time an instance of testclass is requested. Based on the presence of a query string, I want to either return the document_src (although with a few modifications), or simply return the rendered instance... by this, I mean have all the dtml tags that are in the instance evaluated. So, my question is, how do I make Zope evaluate the dtml tags?
Here is what I have so far in my script:
------------ if context.REQUEST.QUERY_STRING == 'editor': print context.raw else: print context
return printed ------------
The 'else' statement simply gives me things like,
<dtml-var standard_html_header>
I also tried 'else: render(context)', which was simply a guess on my part, but I get a Zope error as follows:
Error Type: AttributeError Error Value: validate
Can anyone enlighten me?
Cheers
tim
From: "Bjorn Stabell" <bjorn@exoweb.net>
How do you do dtml-with and dtml-let in a Python script? (I.e. put something on the namespace)
You can't. Scripts can use the DTML namespace in the same way that Python expressions in DTML can, but that's it. On the other hand, you can create (and pass along) all the local variables you want.
How do you give positional (not keyword) arguments to a DTML method; is there any difference?
Keyword arguments are put on top of the namespace. You can't use positional arguments, except the standard (None, _) idiom. DTML was never meant to pass arguments around, that's what the namespace is for, for what that's worth :-P
When is __call__ called, when is __str__ called, and when is index_html called?
When an object with a publishable 'index_html' attribute is the target of a request, that attribute is used. Failing that, or if the object is rendered by calling it from DTML or a Script, __call__ is used. DTML's "var" tag will try to convert whatever you give it into a string, so if you give it an object with a __str__ method, it'll get called.
When does RESPONSE need to be passed; it can always be gotten from the REQUEST, right?
Right.
Are namespace, _, REQUEST, and context just different names for the same thing?
Not quite. The namespace, accessible in DTML as "_", is a pile of objects. The REQUEST is a particular object created by ZPublisher to hold information about the request, such as form variables and URL information. The context (or client, for DTML) is the object on which the method was called. If the DTML Method is the target of the request, or if you pass a client as the first argument when calling it, the Method pushes it onto the namespace. Also, the context (like any other Zope object) is acquisition wrapped. The ultimate acquisition parent of any publsihed object is a special wrapper for REQUEST. All this means that when you ask the namespace for the name "foo", it will end up looking for it in the context, in the context's containers all the way to the root, and the REQUEST. Cheers, Evan @ digicool
When does RESPONSE need to be passed; it can always be gotten from the REQUEST, right?
Right.
Not even REQUEST has to be passed as argument. def foo(self,REQUEST):print REQUEST.lastname == def bar(self): print self.REQUEST.lastname But many manage_* methods use the REQUEST=None and if REQUEST is not None, redirect to 'manage_workspace' or else void. Is there a special little trick in Zope that passes REQUEST as a parameter to say "this is ZMI"? Is REQUEST specially treated compared to other arguments?
Peter Bengtsson wrote:
Is there a special little trick in Zope that passes REQUEST as a parameter to say "this is ZMI"? Is REQUEST specially treated compared to other arguments?
That's the magic of "mapply". Basically, the target of a request gets called by the "mapply" function, which sniffs its call signature and tries to match parameter names to names in the REQUEST, including "REQUEST". If you create a Script and give it parameters like REQUEST and RESPONSE, it will get them when it is the request target. -- Cheers, Evan @ digicool
I knew it! Because when you add a product via the management interface, you actually browse (via the action tag in the form) away to a python def. def manage_addproduct(self, fromwhere, hey, wheredidthiscomefrom, RESPONSE)ยจ Where does mapply() function? Peter
Peter Bengtsson wrote:
Is there a special little trick in Zope that passes REQUEST as a parameter to say "this is ZMI"? Is REQUEST specially treated compared to other arguments?
That's the magic of "mapply". Basically, the target of a request gets called by the "mapply" function, which sniffs its call signature and tries to match parameter names to names in the REQUEST, including "REQUEST". If you create a Script and give it parameters like REQUEST and RESPONSE, it will get them when it is the request target.
-- Cheers,
Evan @ digicool
I'm experimenting with zope, apache and mod_proxy and I'm almost there. I've been following the instructions in: http://www.zope.org/Members/rbeer/caching Including these lines in standar_html_header <dtml-call "RESPONSE.setHeader('Expires', _.DateTime(_.DateTime().timeTime()+ 3600).toZone('GMT').rfc822())"> <dtml-call "RESPONSE.setHeader('Last-Modified', bobobase_modification_time().toZone('GMT').rfc822())"> works great for dtml methods and documents. But how do I tell the client to cache the results of an external method? -- oivvio polite cell +46 (0)709 30 40 30 / phone +46 (0)8 669 64 18 / fax +46 (0)8 84 00 18 varvsgatan 10A / s-117 29 stockholm / sweden
oivvio polite writes:
<dtml-call "RESPONSE.setHeader('Last-Modified', bobobase_modification_time().toZone('GMT').rfc822())">
works great for dtml methods and documents. But how do I tell the client to cache the results of an external method? In the same way.
It is just a bit different how you get hold of "RESPONSE". Your options: 1. you pass RESPONSE as a parameter to the External Method 2. you get REQUEST (somehow) and use "REQUEST.RESPONSE" Your options to get at REQUEST: 1. you pass REQUEST as parameter 2. you have the first parameter "self" and have satisfied the conditions for the External Method calling magic (==> searchable mailing list archive) or pass a Zope object explicitly as parameter "self". Then you can use "self.REQUEST" to access "REQUEST". Dieter
Well Dieter, that worked like a charm. Thanks a lot. I already had the REQUEST object in the External method (although I'll have to admit that I don't have a clue as how to it is actually passed.) I just added from DateTime import DateTime REQUEST.RESPONSE.setHeader('Expires',DateTime(DateTime().timeTime() + 3600).toZone('GMT').rfc822()) REQUEST.RESPONSE.setHeader('Last-Modified', self.bobobase_modification_time().toZone('GMT').rfc822()) in the right places and everything seems to work fine. One other thing. Zope aknowledges changes to Data.fs on the fly but to get it to react to changes in External methods I have to restart zope. During debugging this is kind of tiresome. There must be a simpler way. Right? -- oivvio polite cell +46 (0)709 30 40 30 / phone +46 (0)8 669 64 18 / fax +46 (0)8 84 00 18 varvsgatan 10A / s-117 29 stockholm / sweden
oivvio polite wrote:
One other thing. Zope aknowledges changes to Data.fs on the fly but to get it to react to changes in External methods I have to restart zope. During debugging this is kind of tiresome. There must be a simpler way. Right?
-- oivvio polite
Hi Oivvio You *do not* have to restart Zope, whenever you change your external method. Instead, in the management screen of your external method, just click on the *Save Changes* button to get your changes to the external method become active ;-) --- Flynt
participants (6)
-
Bjorn Stabell -
Dieter Maurer -
Evan Simpson -
Flynt -
oivvio polite -
Peter Bengtsson