Re: [Zope] Fun with Trees
Charlie Wilkinson writes:
I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. I've pretty much figured out that I need a wrapper around objectValues that will filter out the objects that don't have the "add_to_menu" property. This wrapper would be called with dtml-tree's "branches" attribute. I'm trying to do this wrapper in a DTML method and I've gotten all the way to where I have to return a list of "actual objects", so says the DTML Quick Reference.
Is there someone who could 'splain to me how to build a list of objects in DTMLese?
Here's what I have so far (obviously not working):
<dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "REQUEST.set('ret', ret + ' ' + _['sequence-item'])"> </dtml-if> </dtml-in> <dtml-return "_.string.split(ret)"> That's perfect.
Almost surely, your problem results from the fact that "dtml-tree" does not expect "branches" to be a DTML method and does not pass a namespace to it. I do not know, how you can avoid this (other than changing the "dtml-tree" code. Dieter
Charlie Wilkinson writes: After RTFMing and flailing at DTML all night, I'm about stumped. No pun intended. I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. I've pretty much figured out that I need a wrapper around objectValues that will filter out the objects that don't have the "add_to_menu" property. This wrapper would be called with dtml-tree's "branches" attribute. I'm trying to do this wrapper in a DTML method and I've gotten all the way to where I have to return a list of "actual objects", so says the DTML Quick Reference. Is there someone who could 'splain to me how to build a list of objects in DTMLese? Here's what I have so far (obviously not working): <dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "REQUEST.set('ret', ret + ' ' + _['sequence-item'])"> </dtml-if> </dtml-in> <dtml-return "_.string.split(ret)"> [rh] Try (yes, this is tested): <dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "ret.append(id)"> </dtml-if> </dtml-in> <dtml-return ret> Two notes: - the string approach is an unnecessary hack. I changed it to standard Python list idiom - if you append sequence-item it will include your whole method, which presumably is not what you want in your tree. Use id. HTH Rik
On Mon, Jul 03, 2000 at 09:35:06AM +0200, Rik Hoekstra waxed eloquent:
Charlie Wilkinson writes:
[...]
I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. [...] [rh] Try (yes, this is tested): <dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "ret.append(id)"> </dtml-if> </dtml-in> <dtml-return ret>
Two notes: - the string approach is an unnecessary hack. I changed it to standard Python list idiom
It sure looks a lot cleaner, thanks Rik.
- if you append sequence-item it will include your whole method, which presumably is not what you want in your tree. Use id.
Not sure. Supposedly objectValues() returns "actual objects", and I assumed that using sequence-item would be something closer to that. <shrug> The finer points of python are still lost on me, but I'm working on it. The bigger problem seems to be the namespace issue that Dieter was speaking of. When I tried your code, I got Attribute errors on __getitem__. It appears that Tree does not inherit the usual DMTL namespace. I've been looking at Tree trying to figure out how to add it back in or somehow sneak my namespace into it, wondering what I'll break in the process. (But that's what makes Zope so interesting! 8-) -cw- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Charlie Wilkinson - cwilkins@boinklabs.com - N3HAZ Parental Unit, UNIX Admin, Homebrewer, Cat Lover, Spam Fighter, HAM, SWLer... Visit the Radio For Peace International Website: http://www.rfpi.org/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CLOBBER INTERNET SPAM: See!! <http://spam.abuse.net/> Join!! <http://www.cauce.org/> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ QOTD: Failure is not an option. It's bundled with your software.
<snip>
Not sure. Supposedly objectValues() returns "actual objects", and I assumed that using sequence-item would be something closer to that. <shrug> The finer points of python are still lost on me, but I'm working on it.
Hm, you're right of course.
The bigger problem seems to be the namespace issue that Dieter was speaking of. When I tried your code, I got Attribute errors on __getitem__. It appears that Tree does not inherit the usual DMTL namespace. I've been looking at Tree trying to figure out how to add it back in or somehow sneak my namespace into it, wondering what I'll break in the process. (But that's what makes Zope so interesting! 8-)
Yeah tree does some things. What does your tree-code like? Rik
Charlie Wilkinson writes:
On Mon, Jul 03, 2000 at 09:35:06AM +0200, Rik Hoekstra waxed eloquent:
Charlie Wilkinson writes:
[...]
I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. [...] [rh] - if you append sequence-item it will include your whole method, which presumably is not what you want in your tree. Use id.
Not sure. Supposedly objectValues() returns "actual objects", and I assumed that using sequence-item would be something closer to that. <shrug> The finer points of python are still lost on me, but I'm working on it. You are both right.
In principle, you can use "sequence-item" and get the object. Later, when you use it, you can select whatever you need. However, you used: <dtml-call "REQUEST.set('ret', ret + ' ' + _['sequence-item'])"> The "_[...]" calls "...", if this is callable. Thus, "_['sequence-item']" first returns the object and then calls it, if this is possible. In case of a DTML method, the result would be the rendered body of the method. You can use "_.getitem('sequence-item')" to get the object itself and not the result of calling it. Dieter
Charlie Wilkinson writes:
On Mon, Jul 03, 2000 at 09:35:06AM +0200, Rik Hoekstra waxed eloquent:
Charlie Wilkinson writes:
[...]
I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. [...] [rh] Try (yes, this is tested): <dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "ret.append(id)"> </dtml-if> </dtml-in> <dtml-return ret>
The bigger problem seems to be the namespace issue that Dieter was speaking of.
I found a solution that is much easier than hacking the TreeDisplay code: You do not plan to use REQUEST for information about the request but only as a container for a temporary list. This can be achieved without REQUEST <dtml-with "_.namespace(r=[])"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "r.append(_.getitem('sequence-item'))"> </dtml-if> </dtml-in> <dtml-return r> </dtml-with> Dieter
On Mon, Jul 03, 2000 at 10:38:27PM +0200, Dieter Maurer waxed eloquent:
Charlie Wilkinson writes:
On Mon, Jul 03, 2000 at 09:35:06AM +0200, Rik Hoekstra waxed eloquent:
Charlie Wilkinson writes:
[...]
I'm trying to use dtml-tree to create a selective menu of objects based on whether or not the object has an "add_to_menu" property. [...] [rh] Try (yes, this is tested): <dtml-call "REQUEST.set('ret', '')"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "ret.append(id)"> </dtml-if> </dtml-in> <dtml-return ret>
The bigger problem seems to be the namespace issue that Dieter was speaking of.
I found a solution that is much easier than hacking the TreeDisplay code:
You do not plan to use REQUEST for information about the request but only as a container for a temporary list. This can be achieved without REQUEST
<dtml-with "_.namespace(r=[])"> <dtml-in "objectValues()" sort=id> <dtml-if "_.has_key('add_to_menu')"> <dtml-call "r.append(_.getitem('sequence-item'))"> </dtml-if> </dtml-in> <dtml-return r> </dtml-with>
Lots of good ideas, thanks guys! However, I'm still getting an attribute error on __getitem__. I'm trying to figure out how namespaces get passed around in Python to see if there's an easy way to fix this. I've also found a workaround and pondered another: - pass ['Folder','DTML Document'] to optionValues the normal way, i.e.: <dtml-tree branches_expr="objectValues(['Folder','DTML Document'])" skip_unauthorized="1"> <IMG SRC="<dtml-var SCRIPT_NAME>/<dtml-var icon>"> <dtml-if "meta_type == 'Folder'"> <dtml-var title_or_id> <dtml-else> <A HREF="<dtml-var tree-item-url>" TARGET="main"><dtml-var title_or_id></A> </dtml-if> </dtml-tree> ...and then simply use DTML Documents and *only* DTML Documents for stuff I want in the tree menu, primarily CGI forms, some of which might be dynamically generated. I guess if I smack into any limitations with DMTL Documents, I'll have a Document call a method. It's not ideal, but it seems workable enough. The other alternative might be to use ZCatalog with the Tree tag somehow. I think it might do what I need, but I haven't given it much thought. That said, I still think the idea you and Rik have been helping me with is the most "elegant", but I've got a big site to build and very little time. Would it be any easier if instead of a DTML Method I used an ExternalMethod as a wrapper/filter around objectValues? It's very frustrating, as I keep thinking there's *got* to be an easy way to fix this if I only had a half a Zope/Python clue. I'm already reading about as fast as I can! Regards, Charlie -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Charlie Wilkinson - cwilkins@boinklabs.com - N3HAZ Parental Unit, UNIX Admin, Homebrewer, Cat Lover, Spam Fighter, HAM, SWLer... Visit the Radio For Peace International Website: http://www.rfpi.org/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CLOBBER INTERNET SPAM: See!! <http://spam.abuse.net/> Join!! <http://www.cauce.org/> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ QOTD: Failure is not an option. It's bundled with your software.
participants (3)
-
Charlie Wilkinson -
Dieter Maurer -
Rik Hoekstra