First, let me thank both of you for very helpful answers to my questions. I've got the looping through the lines property to generate links working pretty well. And I think I'm getting a better understanding of acquisition. But I still have one problem, and a comment. Using the following looping construct: <dtml-in "myobject.the_lines"> <a href="&dtml-sequence-item;"><dtml-var "_[_['sequence-item']].title"></a> </dtml-in> I get items that are in the acquisition path (and, thus, can be identified by a single id) just fine. However, when I try to process an item in the lines property that looks like this: top_folder.sub_folder.target_folder, as you suggested, I get a "Key Error." Obviously, it's not recognizing the item as a valid path to/descriptor of the object. I'm guessing that there's a trick to format the string properly so it'll be recognized as a valid path. Is that correct, and what might it be? Thanks for the assistance. Finally, a comment. I've been going through ALL of the e-mail archives (I'm up to March 1999. Man, you people talk alot ;) ). And I've seen a number of threads that all seem to be asking about how to do the same thing: simple linking across hierarchies (and thus out of acquisition paths). When I first heard that Zope was object oriented, I thought "Great, finally no need to worry about the locations of files in directory structures. You just call the object up by its unique id, and you'll get it no matter where it is in the ODB." While that is indeed how it works as long as you're in the acquisition path, you're back to specifying "paths" (even if you want to call them explicit object ids) as soon as you want to go lateral across the hierarchy. I guess I don't see why this should be so. As long as the developer is willing to maintain globally unique ids (Zope seems to enforce this already, doesn't it?), shouldn't they be able to access across-hierarchy objects as simply as in-hierarchy objects? In one of the threads on this subject ("OO Paradigm", Jan-Feb 1999), Jim Fulton even seemed to indicate that there is no reason that something like this could be done, albeit with some Python programming or the use of ZTables (http://www.zope.org/pipermail/zope/1999-February/001716.html). Sorry to ramble, but I guess my question is this: Is there some compelling reason to limit simple object reference in Zope to hierarchical acquisition? I think Zope is a marvelous programming environment, and I think it represents a much bigger shift in the web development paradigm than it seems at first glance. Regardless of my complaints about acquisition, I'll be sticking with it. Thanks again for your time. Chris Fassnacht Wisconsin Center for Education Research UW-Madison
Chris Fassnacht wrote:
First, let me thank both of you for very helpful answers to my questions. I've got the looping through the lines property to generate links working pretty well. And I think I'm getting a better understanding of acquisition.
Glad to be of service.
But I still have one problem, and a comment.
[Essentially: Why doesn't acquisition scan the whole database?] Did you realize that this is what your questions boil down to? <wink> Do you really want to wake up every object in the ODB if you make a typo in a property name? Be sure to specify what order objects are searched; this is important! Seriously, one of the most powerful aspects of acquisition is the way it lets you control the search context and ordering. You decide which objects should be included and which are irrelevant, and what overrides what. It's not clear whether you understand the distinction between the containment hierarchy and the acquisition context. The normal structure of the ZODB, with nested folders containing methods and objects, is a familiar organizational convenience. Object IDs are unique *within their container*, but not globally. The hierarchy also provides a *default* acquisition context for each object, since the bare minimum context for an object is the straight line defined by its absolute URL -- the list of containing objects. Acquisition context can be much more convoluted than simple containment, however. At *each step* in the resolution of a URL, an object can be acquired from *any previous object* in the URL. This means that given "A/B/C/D", "A" must be in the root, "B" must be in "A" *or the root*, "C" must be in "A", "B", or the root, etc. Essentially, a URL builds an "environment" (I prefer 'context') step-by-step. You can leap around in the current environment with each new step, and then the target object or method is rendered in this environment. The canonical example of this is the standard_html_* objects. The root always contains default values for these, which can be overridden by including a folder in your URL which contains objects of the same name. You can thus refine your requirements by inserting objects into the URL. One could, for instance, have a URL like "/styles/fancy/framed/extras/js/flash/docs/MyDoc" which accesses the same object as "/docs/MyDoc", but tells it to render using fancy, framed HTML with JScript and Flash animations.
I think Zope is a marvelous programming environment, and I think it represents a much bigger shift in the web development paradigm than it seems at first glance. Regardless of my complaints about acquisition, I'll be sticking with it.
True enough, and good for you!
Evan,
[Essentially: Why doesn't acquisition scan the whole database?]
Did you realize that this is what your questions boil down to? <wink> Do you really want to wake up every object in the ODB if you make a typo in a property name? Be sure to specify what order objects are searched; this is important!
Yeah, this is basically what I was saying. Sounds pretty simple-minded when you put it that way. Another one of those "seemed like a good idea at the time" sort of things.
Seriously, one of the most powerful aspects of acquisition is the way it lets you control the search context and ordering. You decide which objects should be included and which are irrelevant, and what overrides what.
It's not clear whether you understand the distinction between the containment hierarchy and the acquisition context. The normal structure
I think you've hit the nail on the head. I didn't understand that there was any difference between the two. I thought the acquisition context was rigidly defined by the hierarchy.
of the ZODB, with nested folders containing methods and objects, is a familiar organizational convenience. Object IDs are unique *within their container*, but not
Right, and I understand "their container" to mean the default acquisition context provided by the hierarchy, not just an object's folder.
globally. The hierarchy also provides a *default* acquisition context for each object, since the bare minimum context for an object is the straight line defined by its absolute URL -- the list of containing objects.
Acquisition context can be much more convoluted than simple containment, however. At *each step* in the resolution of a URL, an object can be acquired from *any previous object* in the URL. This means that given "A/B/C/D", "A" must be in the root, "B" must be in "A" *or the root*, "C" must be in "A", "B", or the root, etc. Essentially, a URL builds an "environment" (I prefer 'context') step-by-step. You can leap around in the current environment with each new step, and then the target object or method is rendered in this environment.
The canonical example of this is the standard_html_* objects. The root always contains default values for these, which can be overridden by including a folder in your URL which contains objects of the same name. You can thus refine your requirements by inserting objects into the URL. One could, for instance, have a URL like "/styles/fancy/framed/extras/js/flash/docs/MyDoc" which accesses the same object as "/docs/MyDoc", but tells it to render using fancy, framed HTML with JScript and Flash animations.
Wow. This is a fairly mind-blowing concept. You're saying I can pick and choose the stops I make on my way to an object and thereby create a unique collection of contexts (with their associated methods) that can be used to render the final object in the URL? So if I wanted the same information, say Info1, to be formatted for three different audiences, Aud1, Aud2, and Aud3, then I could (after writing the necessarily individualized methods for each audience) have three links like this: Root/Aud1/Info1, Root/Aud2/Info1, Root/Aud3/Info1, even though the containment hierarchy didn't actually reflect any of these URLs in its structure? I'm going to have to think about this some more. It seems almost like a kind of on-the-fly method inheritance. Zope gets deeper every time I look at it.
I think Zope is a marvelous programming environment, and I think it represents a much bigger shift in the web development paradigm than it seems at first glance. Regardless of my complaints about acquisition, I'll be sticking with it.
True enough, and good for you!
By the way, did you have any suggestions on my problem with getting a "multi-context" path (e.g., Root/Aud1/Info1 or Root.Aud1.Info1) out of a lines property and rendered using the looping construct you showed me earlier? I know it's something simple, but I can't find a helpful reference to it anywhere. Thanks again for your time and patience. Chris
Chris Fassnacht wrote:
Wow. This is a fairly mind-blowing concept.
Isn't it, though? :-) This is part of why people talk about the "Zen of Zope".
You're saying I can pick and choose the stops I make on my way to an object and thereby create a unique collection of contexts (with their associated methods) that can be used to render the final object in the URL? So if I wanted the same information, say Info1, to be formatted for three different audiences, Aud1, Aud2, and Aud3, then I could (after writing the necessarily individualized methods for each audience) have three links like this: Root/Aud1/Info1, Root/Aud2/Info1, Root/Aud3/Info1, even though the containment hierarchy didn't actually reflect any of these URLs in its structure?
Exactly.
By the way, did you have any suggestions on my problem with getting a "multi-context" path (e.g., Root/Aud1/Info1 or Root.Aud1.Info1) out of a lines property and rendered using the looping construct you showed me earlier? I know it's something simple, but I can't find a helpful reference to it anywhere.
Mmf. If you *really* need to be able to specify arbitrary paths (there isn't some small collection of locations of interest?) then something like this should do it (I do recommend '/' as a path separator): <dtml-call "REQUEST.set('targobj', Root)"> <dtml-in "_.string.split(path, '/')"> <dtml-call "REQUEST.set('targobj', _.getattr(targobj, _['sequence-item'])"> </dtml-in> As I think I've mentioned before on the list, it would probably save a lot of folks a lot of grief if _['a/b/c'] and _.getattr(obj, 'a/b/c') did this automatically. Hang on a mo'... Here's a patch for Zope 2.0.0's DocumentTemplate/DT_Util.py which does the trick for getattr: 122a123,127
if '/' in name: for namepart in filter(None, split(name, '/')): inst = careful_getattr(md, inst, namepart) return inst
The other behavior I leave as an exercise for someone who likes to hack Python C Extensions (cDocumentTemplate).
Evan Simpson wrote:
Chris Fassnacht wrote:
Wow. This is a fairly mind-blowing concept.
Isn't it, though? :-) This is part of why people talk about the "Zen of Zope".
You're saying I can pick and choose the stops I make on my way to an object and thereby create a unique collection of contexts (with their associated methods) that can be used to render the final object in the URL? So if I wanted the same information, say Info1, to be formatted for three different audiences, Aud1, Aud2, and Aud3, then I could (after writing the necessarily individualized methods for each audience) have three links like this: Root/Aud1/Info1, Root/Aud2/Info1, Root/Aud3/Info1, even though the containment hierarchy didn't actually reflect any of these URLs in its structure?
Exactly.
By the way, did you have any suggestions on my problem with getting a "multi-context" path (e.g., Root/Aud1/Info1 or Root.Aud1.Info1) out of a lines property and rendered using the looping construct you showed me earlier? I know it's something simple, but I can't find a helpful reference to it anywhere.
Mmf. If you *really* need to be able to specify arbitrary paths (there isn't some small collection of locations of interest?) then something like this should do it (I do recommend '/' as a path separator):
<dtml-call "REQUEST.set('targobj', Root)"> <dtml-in "_.string.split(path, '/')"> <dtml-call "REQUEST.set('targobj', _.getattr(targobj, _['sequence-item'])"> </dtml-in>
I'm not sure what your getting at here, but if you want to resolve a path to a URL try: <dtml-with "REQUEST.resolve_url((SCRIPT_NAME + '/path/to/object'))"> blah </dtml-with> -Michel
Michel Pelletier wrote:
I'm not sure what your getting at here, but if you want to resolve a path to a URL try:
<dtml-with "REQUEST.resolve_url((SCRIPT_NAME + '/path/to/object'))"> blah </dtml-with>
Before I shot my mouth off, I should have metioned that this ability comes with a catch. This sort of functionality was necesary for ZCatalog and WebDAV to resolve URLs into Zope objects, but the usage and semantics of path=object-traversal were never standardized. In addition, the solution to serve the needs of the application did not, unfortuatly, jive with ZopeFind and ZCatalog. Brian and I had a hard time expaining the nature of the problem at the team meeting today, so I hope this explains it to everybody. ZopeFind is a method that will start at a container and search for objects that meet certain criteria with the option to recursivly traverse subfolders. Anyone who has used the Find view in the managment interface will be familiar with this, the interface is just an input form to the ZopeFind method that does all the actual work. Zope find returns a list of (relative_path, unwrapped_object) pairs. The relative_path, is *relative to the container from which ZopeFind was executed in the context of*. 'unwrapped_object' is the acutal object, not including any acquisition wrappers, therefore 'object.absolute_url()' just returns the id of the object, because there is are no layers of acquisition wrappers to build the path from. This is not a problem in itself, the absolute url of the object can be built by '(URL1 + relative_path). A further complication however is added because of the way ZCatalog remembers objects. The ZCatalog.Catalog.Catalog class works on the basis of object and their unique identifiers. The unique identifier can be anything at all, it is just used a document id in the class inverted file index that ZCatalog.Catalog.Catalog uses. The ZCatalog.ZCatalog.ZCatalog class, which is the actual Zope objects, used a (jeez) ZCatalog.Catalog.Catalog object as its engine, what it uses as a 'unique identifier' is the absolute *path* of the object, which is identical to the absolute url without SCRIPT_NAME (ie http://machine:port) in front of it; like '/absolute/path/to/object'. It would make no sense to catalog the whole URL, because if you changed the name of the computer or moved the port, your catalogs would break. 'REQUEST.resolve_url(URL)' wants an absolute url beginning with http: (like absolute_url() is supposed to return). ZopeFind returns relative paths with no context, and ZCatalog wants absolute paths. The work arounds between these three systems are simple, but the problem is that there are three seperate APIs in Zope that work with URLs in different ways. Brian and I tackled this problem in ZCatalog immediatly before the final release. The problem was discovered when a bug was reported that ZCatalog did not return proper URLs of objects when the Catalog was not in the root folder. The solution was simple, use absolute URLs everywhere and strip SCRIPT_NAME off of URLs before cataloging them, and with friendly community support, we found this discrepancy. So until we work it out by coming up with a common standard and implimenting it in the 2.1 release, use REQUEST.resolve_url(), ZopeFind and the Catalog with caution. When you absolutly must do it, use it like ZCatalog does and make sure you pass it the resolve_url() the absolute_url() of a properly wrapped object, or that you prepend URL1 to a relative path, and strip SCRIPT_NAME from URLs before calling Catalog methods. -Michel
-Michel
----- Original Message ----- From: Michel Pelletier <michel@digicool.com>
I'm not sure what your getting at here, but if you want to resolve a path to a URL try:
<dtml-with "REQUEST.resolve_url((SCRIPT_NAME + '/path/to/object'))"> blah </dtml-with>
[description of ZCatalog.Catalog.ZCatalog.ZCatalog.Catalog <wink> snipped]
This is all well and good, but *not* what most people who ask this sort of question of the list want (IMNSHO). They want some simple way of getting a properly acquired object using a *relative* path from another acquired object. Sometimes they want to use a pseudo-URL as a name: <dtml-var number/3/the_larch> and other times to resolve a stored path fragment relative to a container: <dtml-with thingy><dtml-var "_[varwithstringpath]"></dtml-with> and yet others to acquire an unresolved object from another object: <dtml-var "_.getattr(eric(), 'half/a/bee')"> Since slashes are not legal in object identifiers, I see no reason why all of the above should not be valid. If there's a reason I haven't thought of, please let me know! stop-me-before-I-patch-again-<wink>-ly y'rs Evan Simpson
At 00:58 09/09/99 , Evan Simpson wrote:
As I think I've mentioned before on the list, it would probably save a lot of folks a lot of grief if _['a/b/c'] and _.getattr(obj, 'a/b/c') did this automatically. Hang on a mo'...
Here's a patch for Zope 2.0.0's DocumentTemplate/DT_Util.py which does the trick for getattr:
122a123,127
if '/' in name: for namepart in filter(None, split(name, '/')): inst = careful_getattr(md, inst, namepart) return inst
There is a method on REQUEST that does this already: def resolve_url: # Attempt to resolve a url into an object in the Zope # namespace. The url must be a fully-qualified url. The # method will return the requested object if it is found # or raise the same HTTP error that would be raised in # the case of a real web request. If the passed in url # does not appear to describe an object in the system # namespace (e.g. the host, port or script name dont # match that of the current request), a ValueError will # be raised. -- Martijn Pieters, Web Developer | Antraciet http://www.antraciet.nl | Tel: +31-35-7502100 Fax: +31-35-7502111 | mailto:mj@antraciet.nl http://www.antraciet.nl/~mj | PGP: http://wwwkeys.nl.pgp.net:11371/pks/lookup?op=get&search=0xA8A32149 ------------------------------------------
Chris Fassnacht wrote:
<stuff deleted>
In one of the threads on this subject ("OO Paradigm", Jan-Feb 1999), Jim Fulton even seemed to indicate that there is no reason that something like this could be done, albeit with some Python programming or the use of ZTables (http://www.zope.org/pipermail/zope/1999-February/001716.html).
Wow. I had no idea anyone was reading my old posts. I feel so special! But seriously, this has been my personal hobby horse for quite a while now, but I've refrained from bugging DC about it (they've been busy). In any case, ZTables does indeed have the 'hierarchy' functionality that we want, but it has yet to be released. A related proposal called 'Topics' popped up on the Zope site yesterday: http://www.zope.org:18200/Members/Amos/TopicProposal , which seems to apply ZTables Hierarchies to ZCatalog albeit with a somewhat different interface. This is EXACTLY what I've been waiting for! I knew you guys would get around to it eventually. With the minor quibble that it would be nice to have logical operators besides 'OR' to chain queries within a Topic, this proposal seems perfect. The one thing that is unclear is whether you can set properties on a Topic, or if you would have to place a Document with properties on it into the Topic. BTW, as this is so useful in contexts other than news/informational, I propose changing the name from Topics to 'Category' or 'ZCategory'. Cheers, Michael Bernstein.
participants (6)
-
Chris Fassnacht -
Evan Simpson -
Evan Simpson -
Martijn Pieters -
Michael Bernstein -
Michel Pelletier