Zope Question : Virtual folders / URL's
Have been reading the docs but still not clear on a few things. I have my site mapped out in my mind. It has URL's like : mysite.com/ (main page) mysite.com/rss (rss content for mysite) mysite.com/<username> (main <username> page) mysite.com/<username>/rss (rss news content feed for <username> page) Where I come from data belongs in a database. I'm happy for all my HTML to be in the ZopeDB but not any application data (users definitions, news items etc etc). So, looking at my URLs I see that there are a mixture of static and virtual folders. mysite.com/index_html is obviously static though it contains dynamic content. Doing this with Zope is easy and obvious. mysite.com/Fred/ is a dynamic page. Fred only exists as a username in a users table and related information in other tables. It's not obvious to me how I go about serving this page because I can't create a static page for every username (nor do I want to). Clearly mysite.com/Fred/rss will use almost identical processing to the mysite.com/rss page, just different parameters so re-using my "rss" generating code is important to me too. I'm know these virtual folders can be served up by Zope. Can someone tell me what I am missing? - Ian Sparks.
First of all, what you want can be done, but it is not that easy. There are a couple problems with your design goal, some Zope's, some yours. Luckily, the alternative is *very* easy ('very' being a relative term here, basicly it means you don't have to re-engineer Zope). You probably know this, but when Zope is tooling down through objects is traverses them according to various rules. First, it does something special (we'll get to that), then it tries to find the next object in line by just seeing if the next object is a subobject of the current (getattr). If that fails it tries to get the next objects as a sub-item of the current (getitem). If that fails, then it gives you a 404 telling you it couldn't find the next element in the URL you provided (you being the client). The special thing it does is it calls __bobo_traverse__. This is a special method. So you override the root level folder's __bobo_traverse__ to see if your 'virtual folder' is a user and then proceed from there. This is the problem: 1) You can't override the root level folder, because it's not a folder, really, it's the entire Zope application and 2) we override it allready so we beat you to it. Further, although simple, I think you will come to hate having all of your users in your root folder namespace. Generally, you want to keep this namespace as unclutered as possible for many reasons. One good reason is that everything in the root folder is acquireable by everything else, so it's 'prime real estate' in Zope. Another is what if one of your users wants to be named index_html? Or rss? Your __bobo_traverse__ method will either have to know all the special names you want priority on and do the users second, or whatever. Complex. Prone to error. What you really want is this: mysite.com/Users/Fred/rss So you need a special object, in this case instanciated with the id 'Users', that takes the next argument in line as a key into a database, and doesn't break acquisition paths along the way and lets you do this fancy URL manipulation. This special object can have a much simpler __bobo_traverse__ method, because it's not also trying to deal with other objects in the same namespace, the 'Users' namespace is dedicated solely to serving these virtual path elements. This special object should also be very generic, not database specific, and should be programmable directly with various SQL code to execute the query you want. This special object allready exists and does everthing you want to do, it's called a ZSQL Method. ZSQL Methods can accept arguments in the URL, and maintain acquisition so you can apply results to 'higher' objects. In fact, you can even chain ZSQL methods together to do multiple database look ups. Lets say you had two ZSQL Methods in the root folder named 'Users' and 'Flavor'. You can now do: mysite.com/Users/Fred/Flavor/Cherry/rss Users traverses 'Fred' as an argument, then *acquires* Flavor, which applies Cherry as a argument, then acquires rss. Nifty eh? -Michel Ian Sparks wrote:
Have been reading the docs but still not clear on a few things.
I have my site mapped out in my mind. It has URL's like :
mysite.com/ (main page) mysite.com/rss (rss content for mysite) mysite.com/<username> (main <username> page) mysite.com/<username>/rss (rss news content feed for <username> page)
Where I come from data belongs in a database. I'm happy for all my HTML to be in the ZopeDB but not any application data (users definitions, news items etc etc).
So, looking at my URLs I see that there are a mixture of static and virtual folders.
mysite.com/index_html is obviously static though it contains dynamic content. Doing this with Zope is easy and obvious.
mysite.com/Fred/ is a dynamic page. Fred only exists as a username in a users table and related information in other tables. It's not obvious to me how I go about serving this page because I can't create a static page for every username (nor do I want to).
Clearly mysite.com/Fred/rss will use almost identical processing to the mysite.com/rss page, just different parameters so re-using my "rss" generating code is important to me too.
I'm know these virtual folders can be served up by Zope. Can someone tell me what I am missing?
- Ian Sparks.
_______________________________________________ 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 )
Thanks Mike, You are right, root/Users/<usernames> makes more sense than root/<usernames>. I looked at what you said, went away and read ZSQL Methods user guide (again). Now I'm back.....
Lets say you had two ZSQL Methods in the root folder named 'Users' and 'Flavor'. You can now do:
mysite.com/Users/Fred/Flavor/Cherry/rss Users traverses 'Fred' as an argument, then *acquires* Flavor, which applies Cherry as a argument, then acquires rss. << So my Zope folder layout looks like this : root index_html (default) Users (SQL method) Flavor (SQL method) I assume I would also need a DTML Document called "rss" because the SQL methods can't actually deliver any content to the client browser? So, if you would be so kind, lead me through how Zope works on this call : mysite.com/Users/Fred/Flavor/Cherry/rss Zope starts to traverse the call from left-to-right? finds "Users", its a SQL method which takes an argument, aha! the argument is "Fred", [Does Zope now run the Users SQL with that argument?] ok, what's left : "Flavor", okay, I have a "Flavor" SQL method here and that takes an argument too, "Cherry" is that argument. Finally, Zope finds "rss", if this is a DTMLDocument or something "servable" it runs it and returns it to the client? If "rss" wasn't there it grabs the index_html page and serves that? ======= Thanks for your help. Like many others I suspect, I see Zope through a cloud. Sometimes I see the outlines of it and it glimmers! But I just can't grasp a picture of the whole. - Ian Sparks.
Ian Sparks wrote:
Thanks Mike,
You are right, root/Users/<usernames> makes more sense than root/<usernames>.
I looked at what you said, went away and read ZSQL Methods user guide (again).
Now I'm back.....
So my Zope folder layout looks like this :
root index_html (default) Users (SQL method) Flavor (SQL method)
I assume I would also need a DTML Document called "rss"
For the sake of this discussion, yes.
because the SQL methods can't actually deliver any content to the client browser?
They return query results, which are a sequence of record objects.
So, if you would be so kind, lead me through how Zope works on this call :
mysite.com/Users/Fred/Flavor/Cherry/rss
Zope starts to traverse the call from left-to-right?
Yes.
finds "Users", its a SQL method which takes an argument, aha! the argument is "Fred",
[Does Zope now run the Users SQL with that argument?]
If you tell it to, check out the 'Advanced' tab on ZSQL Methods. (First, don't forget to specify one argument to the method or else you won't see what I'm talking about).
ok, what's left : "Flavor", okay, I have a "Flavor" SQL method here and that takes an argument too, "Cherry" is that argument.
First it finds Flavor, then it traversed into Flavor, then Flavor find the next element as its argument (once again, if you tell it to). So essentially the answer is yes.
Finally, Zope finds "rss", if this is a DTMLDocument or something "servable" it runs it and returns it to the client?
Yes.
If "rss" wasn't there it grabs the index_html page and serves that?
If rss wasn't there and it was in your URL then you would get a 404 NotFoundError. If 'Cherry' is your last argument then yes, it would acquire the first 'index_html' object that it found, which in this case is the one in the root folder.
=======
Thanks for your help.
Like many others I suspect, I see Zope through a cloud. Sometimes I see the outlines of it and it glimmers! But I just can't grasp a picture of the whole.
- Ian Sparks.
_______________________________________________ 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 )
Thanks again Mike. So my final (I think, for now) question is this : The whole point of Zope is to get a result back so the URL : mysite.com/Users/Fred/Flavor/Cherry/rss is (the way we have discussed it) really a way of saying : "I want an "rss" document containing information related to User=Fred, Flavor=Cherry. So in order to get my content out I just have to do some things with <dtml-with Users> and <dtml-with Flavor> in my "rss" document? (because these SQLMethods will already have been set up & run as part of the URL traversal and are ready to give me data?) I appreciate your patience, - Ian Sparks.
Ian Sparks wrote:
Thanks again Mike.
So my final (I think, for now) question is this :
The whole point of Zope is to get a result back so the URL :
mysite.com/Users/Fred/Flavor/Cherry/rss
is (the way we have discussed it) really a way of saying : "I want an "rss" document containing information related to User=Fred, Flavor=Cherry.
So in order to get my content out I just have to do some things with <dtml-with Users> and <dtml-with Flavor> in my "rss" document?
You don't even have to work that hard, consider what happens: Let's say that your Users method queries a table that contains two columns, name and title. Primary key is 'name'. Your second method queries a table that contains two columns, flavor and size. Primary key is 'flavor'. Users method is called with 'Fred' as argument, this returns a single record object. ZPublisher then tries to find 'Flavor' on that record object, it doesn't have such an attribute, but it CAN acquire it, so it does. It discovers that it is a SQL method and calls that method, *in the context of the first record object* (keep that in mind...). The second method is called with 'Cherry' as a argument. It returns a single record object. Now, ZPublisher tries to find 'rss' in that record object and fails, but it DOES acquire it, *in the context of the second record object which was found in the context of the first*. Now you are in the rss method, but you are also in the context of the second and first result objects, in that order. So in your method, just say: Hi my name is <dtml-var name>. I'm acquired from the first result object. My title is <dtml-var title>. I'm acquired from the first result object. The flavor was <dtml-var flavor>. I'm acquired from the second result object. The size was <dtml-var size>. I'm acquired from the second result object. Note that if a subsequent record object has a column name identical to that of a preceding record object, the subsequent one is acquired first. This means that subsequent results can 'refine' previous ones. Note that this concept of accessing one object in the context of another is what is called Acquisition and all Zope objects support it, not just ZSQL Methods. -Michel
participants (2)
-
Ian Sparks -
Michel Pelletier