Needing a starting point to understand how traversal and acquisition work, would you give me some hints to solve the type of problem below ? In this example company, a subsidiary must establish proposal based on a product list. If it doesn't have products, it must use the headquarter's ones. 1 with this hierarchy, how can i reach the Product list in the Products Folder from Proposal 1 of Subsidiary 1 ? 2 If Products weren't folder but objects and items weren't contained objects but properties of Products, would the solution be the same ? Root/Headquarter | |-- Products (Folder) | | | | | --- item 1 (objects) | --- item 2 '' | --- item 3 '' | | | | | |-- Proposals (Folder) | | | | | --- Proposal x (object) | |---Subsidiary 1---- | | | |-- Products (Folder) | | | --- no objects | | | | | |-- Proposals (Folder) | | | | | --- Proposal 1 (object) v -- Andre PZP Enthusiast
At 01:14 PM 1/28/2003, D2 wrote:
Needing a starting point to understand how traversal and acquisition work
As a starting point, about 90% of what you need to know about acquisition can be summarized thus: 1. Acquisition works by containment or context. 2. Containment trumps (precedes) context. To put this less formally, the relationship defined between two objects in the ZMI is more tightly bound than the relationship suggested by the construction of a URL. This should make a lot of sense, hopefully. Traversal is mostly a fancy way of building an acquisition context or specifying a particular object to render. Since containment trumps context, it follows that traversal should be thought of as a less optimal way to use acquisition. I would suggest that containment-oriented design (not traversal) should be your default choice for an acquisition strategy. There are cases that call for acquisition by context and heavy traversal, but containment is easier to design for and more generally useful. In most projects I've done, the need to perform significant traversal indicates that some refactoring may be in order.
In this example company, a subsidiary must establish proposal based on a product list. If it doesn't have products, it must use the headquarter's ones.
1 with this hierarchy, how can i reach the Product list in the Products Folder from Proposal 1 of Subsidiary 1 ?
Since it sounds like the purpose of your hierarchy is to drill down from general to specific, not to partition different levels of security, what about the following: / +---Products/ - item1 - item2 - item3 +---Sub1/ - item1 - item3 +---Proposals/ +---Etc/ The URL: /Products/Sub1/item1 will find the item1 object in the Sub1 folder. The URL: /Products/Sub1/item2 will find the item2 object in the folder just above Sub1. The name item2 can't be resolved by Sub1, but *can* be resolved by Sub1's container. Ta da! It works and you're done. Not bad, eh? This pattern is easy enough to nest if you should need more than two layers, BTW.
2 If Products weren't folder but objects and items weren't contained objects but properties of Products, would the solution be the same ?
Probably not, the way you have it, unless you specifically designed the objects to work that way. If an object can't resolve a name, it will look in its container object, in its container's container, etc., and then back up the chain defined by context. It won't be looking for an object named Products (necessarily) that can resolve the method item1, but for *any* object in the acquisition chain that can resolve "item1". You would probably need to give each different Products object a different name so that you could define a "fall-through" acquisition relationship, thus: /hq_products/sub1_products/item_property In this example, hq_products is the same type of object as sub1_products... they just have different methods/attributes available. When item_property *isn't* resolved by sub1_products, you've ensured that there is an object further up in the acquisition chain which *can* resolve the name (assuming the name can be resolved at all). I'm assuming that hq_products is contained by something found in the containment hierarchy of sub1_products. I'm pretty sure you'll have a difficult time pulling this off if you don't give the different Product objects different names... and that's a requirement that may impose significant limitations. If you're locked into the hierarchy you've defined, you'll probably need to create some kind of "observer" or "viewer" method that traverses your hierarchy in specifically designated ways under specific conditions. This is easy enough to do, but I would suggest that designing your hierarchy to suit your acquisition requirements might be the simpler, faster, and more durable solution. $.02... HTH Dylan
Hi Dylan, Thanks for replying. Dylan Reinhardt a écrit:
At 01:14 PM 1/28/2003, D2 wrote:
Needing a starting point to understand how traversal and acquisition work
As a starting point, about 90% of what you need to know about acquisition can be summarized thus: 1. Acquisition works by containment or context. 2. Containment trumps (precedes) context.
To put this less formally, the relationship defined between two objects in the ZMI is more tightly bound than the relationship suggested by the construction of a URL. This should make a lot of sense, hopefully.
Traversal is mostly a fancy way of building an acquisition context or specifying a particular object to render. Since containment trumps context, it follows that traversal should be thought of as a less optimal way to use acquisition.
I would suggest that containment-oriented design (not traversal) should be your default choice for an acquisition strategy. There are cases that call for acquisition by context and heavy traversal, but containment is easier to design for and more generally useful. In most projects I've done, the need to perform significant traversal indicates that some refactoring may be in order.
Well, several comments : in context._setObject() context *is* containment ? So what is the difference ? (maybe the answer is below) Can i say, that containment is the *real* containment of an object (URI ?) and context is the object's containment + (eventually but not necessarily) other containments, so in the example above, context is only composed of containment, that acquisition is Zope's natural way to find an object or a property, that objects have properties containing the acquisition parameters and that they are read by the acquisition mechanism (aq_methods), that traversal is a way to pass to acquisition, parameters that are not contained in the object's acquisition properties, modifying acquisition's behaviour,
In this example company, a subsidiary must establish proposal based on a product list. If it doesn't have products, it must use the headquarter's ones.
1 with this hierarchy, how can i reach the Product list in the Products Folder from Proposal 1 of Subsidiary 1 ?
Since it sounds like the purpose of your hierarchy is to drill down from general to specific, not to partition different levels of security, what about the following:
/ +---Products/ - item1 - item2 - item3 +---Sub1/ - item1 - item3 +---Proposals/ +---Etc/
The URL: /Products/Sub1/item1 will find the item1 object in the Sub1 folder.
The URL: /Products/Sub1/item2 will find the item2 object in the folder just above Sub1.
The name item2 can't be resolved by Sub1, but *can* be resolved by Sub1's container. Ta da! It works and you're done. Not bad, eh?
This pattern is easy enough to nest if you should need more than two layers, BTW.
That's the way i did it for shared properties such as the company name, headquarters adress, company web site, etc. And it works pretty well. But as there are several ways to organize the hierarchy, +---Products/ +---Sub1/ +---Sub2/ +---Proposals/ +---Sub1/ +---Sub2/ or +---Subsidiary1/ +---Products/ +---Proposals/ and as an object can't be contained in different objects, i wouldn't be able to use containment-oriented design only. In your suggestion, if i want to show all the objects related to Sub1, (Sub1.Proposals, Sub1.Products, Sub1.Employees,etc.) i suppose that i'll have to put in each object a property *subsidiary* containing the id of the subsidiary to wich belongs the object and to use traversal (creating what you call *observer* or *viewer* ?) to reach all the objects in the different containers (Products, Proposals, Employee...). Isn't it ? If that's true, in what direction must i go ? (un)restrictedTraverse and family or something else ?
2 If Products weren't folder but objects and items weren't contained objects but properties of Products, would the solution be the same ?
Probably not, the way you have it, unless you specifically designed the objects to work that way.
If an object can't resolve a name, it will look in its container object, in its container's container, etc., and then back up the chain defined by context. It won't be looking for an object named Products (necessarily) that can resolve the method item1, but for *any* object in the acquisition chain that can resolve "item1". You would probably need to give each different Products object a different name so that you could define a "fall-through" acquisition relationship, thus:
/hq_products/sub1_products/item_property
In this example, hq_products is the same type of object as sub1_products... they just have different methods/attributes available.
When item_property *isn't* resolved by sub1_products, you've ensured that there is an object further up in the acquisition chain which *can* resolve the name (assuming the name can be resolved at all). I'm assuming that hq_products is contained by something found in the containment hierarchy of sub1_products. I'm pretty sure you'll have a difficult time pulling this off if you don't give the different Product objects different names... and that's a requirement that may impose significant limitations.
If you're locked into the hierarchy you've defined, you'll probably need to create some kind of "observer" or "viewer" method that traverses your hierarchy in specifically designated ways under specific conditions. This is easy enough to do, but I would suggest that designing your hierarchy to suit your acquisition requirements might be the simpler, faster, and more durable solution.
$.02... HTH
Out of curiosity, where may i find the meanings of those acronyms HTH and so on ? Andre
Dylan
_______________________________________________ Zope maillist - Zope@zope.org http://lists.zope.org/mailman/listinfo/zope ** No cross posts or HTML encoding! ** (Related lists - http://lists.zope.org/mailman/listinfo/zope-announce http://lists.zope.org/mailman/listinfo/zope-dev )
-- Andre PZP Enthusiast
At 06:51 AM 1/29/2003, D2 wrote:
Well, several comments : in context._setObject() context *is* containment ?
Context is context, oddly enough. Containment is when one object is a subobject of another. Think of this ZMI hierarchy: / +---a/ - b - c as being equivalent to: class container: def __init__(): self.b = some_class() self.c = some_class() a = container() Thus, a *contains* instances of some_class called b and c.
Can i say, that containment is the *real* containment of an object (URI ?)
If by "real" you mean "as set in the ZMI," then yes.
and context is the object's containment + (eventually but not necessarily) other containments, so in the example above, context is only composed of containment,
No. Context is determined for each request. Context is fully dynamic, whereas containment is static (between changes, anyway).
that acquisition is Zope's natural way to find an object or a property,
I would say so. Saying it's the "natural way" may be a matter of opinion, but acquisition is, perhaps, Zope's most characteristic feature and the one I rely most heavily upon.
that objects have properties containing the acquisition parameters and that they are read by the acquisition mechanism (aq_methods),
Objects have acquisition wrappers. All other methods and attributes are actually provided by these wrappers.
that traversal is a way to pass to acquisition,
You don't really "pass to" acquisition. Objects have containment the moment they are instatiated. Contextual acquisition is created by each request and can be manipulated during the request. Traversal is a way of manipulating your objects directly. It is typically used when standard acquisition won't be able to find something it needs. Your example of needing to walk back up the tree and down another branch with identical folder names would require traversal since acquisition alone isn't going to do that for you.
+---Subsidiary1/ +---Products/ +---Proposals/
and as an object can't be contained in different objects, i wouldn't be able to use containment-oriented design only.
With the above, you could store the HQ/default items in the folder just above Sub1... for both products and proposals. Another option would be to create folders just above Sub1 called, say product_defaults and proposal_defaults and use something like this as the URL: /product_defaults/Subsidiary1/Products/product_name That way, a container has been specified which can resolve product_name in the event that Subsidiary1/Products is unable to do so. But that's ugly. If you are reasonably experienced with Python and are feeling a bit more ambitious, it's not that hard to create your own Folder object and override implicit acquisition with specific acquisition routines for specific types of attributes. At that point, you can drop product_defaults from your URL and put it pretty much anywhere you want.
In your suggestion, if i want to show all the objects related to Sub1, (Sub1.Proposals, Sub1.Products, Sub1.Employees,etc.) i suppose that i'll have to put in each object a property *subsidiary* containing the id of the subsidiary to wich belongs the object
Each object will have an aq_parent property that will tell you as much.
and to use traversal (creating what you call *observer* or *viewer* ?) to reach all the objects in the different containers (Products, Proposals, Employee...). Isn't it ?
Perhaps... your need for traversal depends on the degree to which you want to design around containment.
If that's true, in what direction must i go ? (un)restrictedTraverse and family or something else ?
I'd stick with restrictedTraverse by default and only use unrestrictedTraverse the way one might use the Manager proxy role... very carefully.
Out of curiosity, where may i find the meanings of those acronyms HTH and so on ?
HTH = Hope That Helps... and I hope it does. :-) Some stuff that you may find helpful: http://www.zope.org/Members/Amos/WhatIsAcquisition http://www.ccs.neu.edu/home/lorenz/research/acquisition/ExtensionClass/Acqui... http://www.zope.org/Documentation/Books/ZDG/current/next http://www.zope.org/Members/jim/Info/IPC8/AcquisitionAlgebra/ http://www.zope.org/Members/4am/aq_trees And for acronyms... http://www.geocities.com/SouthBeach/Lagoon/9819/acronyms.html LMKOAP, Dylan
Thanks for your help I'll read your reply and the material referenced in. I think i need to digest that, as i understood that context is context and that under certain circumstances, context may be context or it may be context :) I'll come back to validate my understanding. -- Andre PZP Enthusiast
One quick correction... At 06:51 AM 1/29/2003, D2 wrote:
in context._setObject() context *is* containment ?
I didn't read this question correctly before and gave an unhelpful answer. The context object contains, among other things, a reference to your current container object. Using container-related methods on context (the object) has the effect of applying them to a specific container object... which container object that is will be determined by context (as in the environment, not the context object). Using container methods on the context object allows you to generalize your code, but it's the same thing as if you hard-coded a folder name and applied the same methods to it: any objects you create using this technique will have a containment relationship with a specific container. Which container that is can be determined by context if you wish. Sorry if that's pretty jargon-dense... it's a trickier question than I realized at first. Dylan
Thanks for the links, i had read the DevGuide when i began with Zope, but found it esoteric at that time. My knowledge evolving, it's easier to read What i understood, Containment: the objects' house and the path to the object from the root context: the road used to reach the object. A property will be searched first in the object's containment, then in its parents ones, to the root. If the containment-search failed, the search will be made in the context. The context may be searched by using basic acquisition or by calling methods on wrappers (aq_inner, aq_chain, aq_parent, _of_, etc. . My example company will be a mix of containment and context design. Company/ Headquarters/ Subsidiary 1/ | to n /(HQ and Sub will be called departments) Products/ - Items Property 'related_to' (the HQ or a Sub) Property 'belongs_to' (the id of HQ or the Sub which sells the product) Proposals/ - Items Property 'related_to' (the HQ or a Sub) Property 'belongs_to' (the id of HQ or the Sub editing the proposal) - addMethod - listMethod When i want to add a product or a Proposal i use : Company/<Department_id>/<Products_or_Proposals/addMethod : the object will inherit of the department properties but will be stored in <Products_or_Proposals> that will be the context. Departements will be one of the aq_parent of the object. When i want to list all Products or Proposals i use Company/Products_or_Proposals/listMethod for a specific Subsidiary i use Company/<department_id>/Products_or_Proposals/listMethod as i need to have the sub's specific Products + the HQ's Products, i test the 'related_to' and 'belongs_to' properties. Not too stupid ? Andre Dylan Reinhardt a écrit:
One quick correction...
At 06:51 AM 1/29/2003, D2 wrote:
in context._setObject() context *is* containment ?
I didn't read this question correctly before and gave an unhelpful answer. The context object contains, among other things, a reference to your current container object.
Using container-related methods on context (the object) has the effect of applying them to a specific container object... which container object that is will be determined by context (as in the environment, not the context object).
Using container methods on the context object allows you to generalize your code, but it's the same thing as if you hard-coded a folder name and applied the same methods to it: any objects you create using this technique will have a containment relationship with a specific container. Which container that is can be determined by context if you wish.
Sorry if that's pretty jargon-dense... it's a trickier question than I realized at first.
Dylan
_______________________________________________ Zope maillist - Zope@zope.org http://lists.zope.org/mailman/listinfo/zope ** No cross posts or HTML encoding! ** (Related lists - http://lists.zope.org/mailman/listinfo/zope-announce http://lists.zope.org/mailman/listinfo/zope-dev )
At 02:41 PM 1/30/2003, D2 wrote:
Thanks for the links, i had read the DevGuide when i began with Zope, but found it esoteric at that time. My knowledge evolving, it's easier to read
It's a big hurdle, that one. But once you know what it is, the docs are brilliant. :-)
What i understood, Containment: the objects' house and the path to the object from the root context: the road used to reach the object. A property will be searched first in the object's containment, then in its parents ones, to the root. If the containment-search failed, the search will be made in the context.
That's most of it. The one extra wrinkle is, any object specified in context also has its own containment which (IIRC) also precedes objects further up the acquisition chain.
The context may be searched by using basic acquisition or by calling methods on wrappers (aq_inner, aq_chain, aq_parent, _of_, etc. .
I'm not sure if "searched" is the word I'd use, but it sounds like you're headed in the right direction. Also, just FYI, the __of__ method has four underscores. It's a heck of a good trick to know, that one. :-)
When i want to add a product or a Proposal i use : Company/<Department_id>/<Products_or_Proposals/addMethod : the object will inherit of the department properties but will be stored in <Products_or_Proposals> that will be the context.
So far so good...
Departements will be one of the aq_parent of the object.
I'm not sure I follow you here. If an object is installed in Products, then Products will be its parent. When you call: Company/department/Products/some_product then department will be *in* the acquisition chain for some_product, but Products will still be its parent. I might be getting nit-picky at this point... what you've described sounds like it could work. But for the most part, Acquisition needs to be understood, not manipulated. It's rarely the case that you'll use the acquisition wrapper methods unless you're developing your own Python Products... at which point, your solution would be radically different.
as i need to have the sub's specific Products + the HQ's Products, i test the 'related_to' and 'belongs_to' properties.
I'm not sure I see how that improves on using a folder hierarchy to group products. Either way you're segregating your products by owner, and a folder hierarchy would make that segregation far easier to inspect and enforce... also you may run into trouble when you want one version of a product for one department but want the rest of the departments to use the HQ version. I'm sure it's quite possible to make your solution feasible, but there may be challenges along the way. But then again, there are always challenges, aren't there? ;-)
Not too stupid ?
Not stupid at all... but at a certain point, the best way to tell if you have a design weakness is to give it a try. I'd say give it a go. Happy Zoping, Dylan
participants (2)
-
D2 -
Dylan Reinhardt