You are not logged in Log in Join
You are here: Home » Zope Documentation » Books » The Zope Book Releases » The Zope Book (2.5 Edition) » Creating Basic Zope Applications

Log in
Name

Password

 
Previous Page Up one Level Next Page Creating Basic Zope Applications Comments On/Off Table of Contents

Chapter 6: Creating Basic Zope Applications

In Chapter 3, "Using Basic Zope Objects" and Chapter 4, "Dynamic Content with DTML" you learned about basic Zope objects and DTML. In this chapter you'll see how you can build simple but powerful web applications using these tools. In later chapters of the book you'll discover more complex objects and more complex DTML. However, the design techniques covered in this chapter are still relevant.

Anonymous User - July 17, 2002 10:59 am:
 I would suggest that this be one of the first chapters. Kind of like the " A Stroll Through Perl" in Chapter
 1 of "Learning Perl" book. This could then be followed by chapters that go into all the "sorid" details of
 Zope use and management.

Note: in chapter 3, "Basic Zope Objects", we explained how Zope Page Templates are new to Zope and should be used for presentation. We have not yet converted this chapter over to use Page Templates instead of DTML. We will be rewriting this chapter soon to reflect new methedologies based on page templates soon.

Anonymous User - Jan. 14, 2003 11:22 am:
 This has been promissed for a year now, the previous comments lamenting this fact were taken out. What needs
 to happen here? Most Zopers are quite eager for this chapter!!!
Anonymous User - Jan. 14, 2003 12:52 pm:
Th comments were removed because they were not helpful and becoming more inflammatory and annoying every day.
 The writer that made this promise in the 2.5 edition of the book is no longer working on the Book. This is a
 now a volunteer effort. A new version of the Zope Book is available at
http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition. Its Creating Basic Zope Applications chapter has
 not yet been edited, but it is on the plate. It will hopefully have ZPT examples.

As of version 2.5, Zope comes with a number of sample applications. Look in the "Examples" folder in the root folder. These example applications demonstrate new Zope features. Page Templates and Python Scripts are both given close attention in these online examples.

Building Applications with Folders

Folders are the "basic building blocks" of Zope applications. Folders allow you to organize your Zope objects, and actively participate in your web applications. Folders are given behavior by adding scripts to them.

Anonymous User - Jan. 14, 2003 6:36 pm:
 TEST

Scripts and folders work together to build simple applications. Folders provide structure for your information and also provide a framework for your site's behavior. Later in this chapter, an example of a simple guest book application based on this design concept is given. A folder is used to hold the methods, scripts and data of the guest book application, the scripts provide behavior that define how the application works, and the methods provide presentation to the application.

For example, suppose you have an Invoices folder to hold invoices. You could create objects inside that folder named addInvoice and editInvoice to allow you to add and edit invoices. Now your Invoices folder becomes a small application.

Zope's simple and expressive URLs are used to work with the invoices application. As you've seen, you can display a Zope object by going to its URL in your browser. So for example, the URL http://localhost:8080/Invoices/addInvoice calls the addInvoice object on the Invoices folder. This URL might take you to a screen that lets you add an invoice. Likewise, the URL http://localhost:8080/Invoices/editInvoice?invoice_number=42 calls the editInvoice object on the Invoices folder and passes it the argument invoice_number with a value of 42. This URL could allow you to edit invoice number 42.

Calling Objects on Folders with URLs

The invoices example demonstrates a powerful Zope feature. You can call an object on a folder by going to a URL that consists of the folder's URL followed by the id of the object. This facility is used throughout Zope and is a very general design pattern. In fact you are not just restricted to calling objects on folders. You'll see later how you can call objects on all kinds of Zope objects using the same URL technique.

Anonymous User - Sep. 10, 2002 4:24 pm:
 Calling objects ON folders? This strikes me as non-sensical. Do you mean IN folders? I have never heard the
 phrase to call something "on" something else. If this is an advanced programming idea, please explain.
 Also, is object to be synonymous with method here?
Anonymous User - Sep. 22, 2002 10:22 am:
 Well, this is the miracle of URL traversal, object resolution and Acquisition.
 So far the explanation left us ignorant staring open mouthed at wonders.
 The best explanation of Acquisition so far i have seen is in
 http://webdev.zopeonarope.com/ch8-10available pages 199-210 (download pdf)
 Also, a DTML Document is not called on something, its just called.
Anonymous User - Nov. 19, 2002 1:23 pm:
 My instinctual visualization of this, admittedly strange, turn of phrase, is that the object is applied to
 the folder (object). The use of on is similar to it's usage in a phrase such as: I'm going to sic my dog on
 you, where sic == call, dog is the object and you are the folder:)

For example suppose you want to call an object named viewFolder on one of your folders. Perhaps you have many different viewFolder objects in different locations. Zope figures out which one you want by first looking in the folder that you are calling the object on. If it can't find the object there it goes up one level and looks in the folder's containing folder. If the object can't be found there it goes up another level. This process continues until Zope finds the object or gets to the root folder. If Zope can't find the object in the root it gives up and raises an exception.

You'll see this kind of dynamic behavior in many different places in Zope. This technique is called acquisition. A folder is said to acquire a object by searching for the object in its containers.

Anonymous User - Sep. 2, 2002 11:56 pm:
 How is "aquisition" different from "inheritance" (a term commonly used in object-oriented discussions)?
Anonymous User - Sep. 22, 2002 10:38 am:
 Objects in the ZODB have a place.
 Acquisition searches in the outer *context* of the object, ie the objects place.
 Inheritance searches inside the object (python objects *contain* their constituent parts) and its class
 derivation ancestry.
Anonymous User - Sep. 22, 2002 10:42 am:
 Objects in the ZODB have a place.
 Acquisition searches where this object is contained in;
 that is the outer *context* of the object, ie the objects place.

 Inheritance searches inside the object (objects *contain* their constituent parts) and its class derivation
 ancestry.

The Special Folder Object index_html

As you've seen, folders can acquire all kinds of objects. There is one special object that Zope uses to display a folder. This object is named index_html.

The index_html object provides a default view of the folder. This is analogous to how an index.html file provides a default view for a directory in Apache and other web servers.

Anonymous User - Aug. 7, 2002 3:49 pm:
 Is there a reason index_html is used in Zope instead of index.html?
Anonymous User - Aug. 15, 2002 8:38 am:
 Trivial. index_html is a legal python name. index.html would have to be 
 accessed as self["index.html"] etc.
Anonymous User - Jan. 28, 2003 12:43 pm:
 Maybe a trivial question, but is index_html not a method as opposed to an object? If it is an object, when
 method is used (possibly aquired) to render it?

For example, if you create an index_html object in your Invoices folder and view the folder by clicking the View tab or by visiting the URL http://localhost:8080/Invoices/, Zope will call the index_html object on the Invoices folder.

A folder can also acquire an index_html object from its parent folders just as it can acquire any object. You can use this behavior to create a default view for a bunch of folders all in one place. If you want a different default view of a given folder, just create a custom index_html object in that folder. This way you can override the index_html object defined higher up.

Anonymous User - Apr. 27, 2002 11:08 pm:
 Its still not clear to me - when I create a new index_html, do I want to create a template, a method, a dtml
 document, or can I create any of these and whatever has the URL gets executed? Is there a preferred or best
 practice approach?
Anonymous User - May 1, 2002 8:57 pm:
 You can create any of them as suits your needs.

Building the Zope Zoo Website

In this section, you'll create a simple web site for the Zope Zoo. As the Zoo webmaster, it is your job to make the web site easy to use and manage. Here are some things you'll need:

  • Zoo users must easily move around the site, just as if they were walking through a real Zoo.
  • All of your shared web layout tools, like a Cascading Style Sheet (CSS), must be in one easy to manage location.
  • You must provide a simple file library of various documents that describe the animals.
  • You need a site map so that users can quickly get an idea of the layout of the entire Zoo.
  • A Guest book must be created so that Zoo visitors can give you feedback and comments about your site.
  • A what's new section must be added to the guest book so that you can see any recent comments that have been added.

Navigating the Zoo

In order for your navigation system to work, your site will need some basic structure through which to navigate. Create some folders in your Zope system that represent the structure of your site. Let's use a zoo structure with the following layout, as shown in [5-1].

Anonymous User - Sep. 22, 2002 10:54 am:
 Order of presentation: Maybe first index_html, and then navigation?
Anonymous User - Dec. 15, 2002 2:39 pm:
 "Create some folders in your Zope system"...
 Yeal, right, some folder, but how do i it?
 from the manager? or mkdir?
Anonymous User - Dec. 15, 2002 5:08 pm:
 From the ZMI.  Everything in this chapter is about using Zope through the ZMI.

Zoo folder structure.

Figure 5-1 Zoo folder structure.

The main structure of the Zope Zoo contains three top level folders, Reptiles, Mammals and Fish. To navigate your site, users should first go to your home page and click on one of the top level folders to enter that particular part of the Zoo. They should also be able to use a very similar interface to keep going deeper into the site; i.e. the snakes section. Also, the user should be able to back out of a section and go up to the parent section.

Anonymous User - Sep. 22, 2002 10:48 am:
 style: please dont mix singular "user" and "plural"

You can accomplish this easily with Zope. In your ZopeZoo folder, create a DTML Method called navigation:


<ul>
<dtml-in expr="objectValues('Folder')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li><br>
</dtml-in>
</ul>
Anonymous User - May 17, 2002 11:03 am:
 The <br> element isn't needed to get a new line in the browser.

The method you just created shows a list of links to the various sub-sections of the zoo. It's important to notice that this method can work on any zoo folder since it makes no assumptions about the folder. Also since we placed this method in the ZopeZoo folder, all the zoo folders can acquire it.

Now, you need to incorporate this method into the site. Let's put a reference to it in the standard_html_header object so that the navigation system is available on every page of the site. Your standard_html_header could look like this:


<html>
<head><title><dtml-var title></title></head>
<body>
<dtml-var navigation>
Anonymous User - May 29, 2002 2:01 pm:
 <dtml-var navigation>
 i cant get this code to work, should it be <dtml-var index_html>?
Anonymous User - May 30, 2002 11:08 am:
 I have the same problem
Anonymous User - May 30, 2002 12:50 pm:
 i put it into the index_html file just below the standard header call and it finally worked.
Anonymous User - June 14, 2002 10:57 pm:
 standard_html_header is a dtml method. If you copy standard_html_header from the root folder into your
 ZopeZoo folder and modify it, it will work.
...Therefore I assume that if you created it as a dtml method (instead of a page template as I initially did)
 that it would work properly.
Anonymous User - Sep. 13, 2002 3:17 am:
 Yes, it's not stated explicitly, but you need to make this a DTML method.
Saman - Nov. 15, 2002 7:21 am:
 Starnge thinhg,when I would create the folowing objects:standard_html_header and
 index_html,the code would not function,but if I copy them from the root folder and then edit the source code
 it will strangely function...my guess is that it has to do something with the object Id
Anonymous User - Jan. 4, 2003 11:14 pm:
 When I copied the standard_html_header from the root and pasted into file folder ZopeZoo it made if
copy_of_standard_html_header and resisted efforts to change the name to standard_html_header. For some reason
 it keeps thinking that my ZopeZoo folder is the same as the root! Any help? Is this a zope bug?

Next we need to add a front page to the Zoo site and then we can view the site and verify that the navigation works correctly.

Adding a Front Page to the Zoo

Now, you need a front page that serves as the welcome screen for Zoo visitors. Let's create a DTML Method in the ZopeZoo folder called index_html with the following content:


<dtml-var standard_html_header>

  <h1>Welcome to the Zope Zoo</h1>

  <p>Here you will find all kinds of cool animals.  You are in
  the <b><dtml-var getId></b> section.</p>

<dtml-var standard_html_footer>
twalter - Apr. 20, 2002 8:04 pm:
 I know it is stated correctly here, but since I tripped, I would add comments to the effect that a DTML
 Document called index_html will not work. It must be a DTML Method. (You can see my comments also in "Using
Basic Zope Objects" chapter, "Comparing DTML Documents and Methods" section. If it had been there, I probably
 would not have needed anything here also.)
Anonymous User - Apr. 27, 2002 11:22 pm:
 Why a method - it looks like content - is index_html an exception to the doc v. method rule because it
 attaches to the folder instead of creating a new file? (I'm guessing.)
Anonymous User - May 27, 2002 12:17 am:
 I didn't catch that either, until I hit it, couldn't figure it out, and read the above comment.
Anonymous User - June 4, 2002 7:00 pm:
 Just to confirm the earlier comment, I had to use a DTML Method to get it to work too.
Anonymous User - June 14, 2002 11:01 pm:
Is it just me or does the fact that a dtml method is required and a document doesn't work a bit arbitrary?
Maybe
I don't fully understand the semantics of dtml docs vs methods, but if there's an expert who can discuss that
 at this point in the tutorial, it would likely be very useful.
Anonymous User - June 21, 2002 5:46 am:
 Well, it's just a question of namespaces. 

 objectValues() is [] when used in a DTML document -> a document is an object 
 that can properties and subobjects. In the case of a DTML document it can 
 only have properties. 

 objectValues() in a DTMLMethod lists all siblings of the method because a 
 Method is not a "Zope Object". 

 yacc
Anonymous User - Aug. 28, 2002 4:25 am:
 I do not understand the above explication: "a document is an object that can 
 (have) properties an subojects"(???) How can a document have subobjects?
 The method "objectValues" belongs to class ObjectManager. How is this connected 
 to either DTML Document or DTML Method?
Anonymous User - Oct. 17, 2002 8:03 am:
 it's easy, first try it with DTML document, then with DTML method
 and if none works, go download tomcat

Take a look at how your site appears by clicking on the View tab in the root folder, as shown in [5-2].

Anonymous User - June 20, 2002 9:51 am:
 I did everything written in your documentation but I didn't succeed.
 I don't see the following lines :
 . Fish
 . Mammals
 . Reptiles

 It seems   that navigation was never called.
 Can you help me
Anonymous User - June 26, 2002 8:05 am:
 I have same problem
Anonymous User - June 26, 2002 8:15 am:
 Petrov Andey: index_html must be DTML method
Anonymous User - July 1, 2002 7:14 am:
 I had the same problem. Both index_html and standard_html_header are DTML methods. (I also tried it with the
 header as a DTML doc and that made no difference)
Anonymous User - July 1, 2002 7:19 am:
 Solved it! EVERYTHING seems to need to be a method rather than a document. (So that's: index_html,
 standard_html_header, navigation)
 Is there any point using DTML documents then?
Anonymous User - Aug. 28, 2002 3:30 pm:
 Make sure that <dtml-var standard_html_header> is not in your navigation method
Saman - Nov. 15, 2002 8:09 am:
 This is wrong...the method objectvalue('folder') loks for the name of the subfolders in the curent folder,if
 you dont see the navigation when you click on rptile its because within the reptile folder there os no
 subfolders.how ever if you create some foldersthen you will be a ble to see navigation.So the coplet Design
 of this navigation is wrong...

Zope Zoo front page.

Figure 5-2 Zope Zoo front page.

Here you start to see how things come together. At the top of your main page you see a list of links to the various subsections. These links are created by the navigation method that is called by the standard_html_header method.

You can use the navigation links to travel through the various sections of the Zoo. Use this navigation interface to find the reptiles section.

Zope builds this page to display a folder by looking for the default folder view method ,index_html. It walks up the zoo site folder by folder until it finds the index_html method in the ZopeZoo folder. It then calls this method on the Reptiles folder. The index_html method calls the standard_html_header method which in turn calls the navigation method. Finally, the index_html method displays a welcome message and calls the standard_html_footer.

What if you want the reptile page to display something besides the welcome message? You can replace the index_html method in the reptile section with a more appropriate display method and still take advantage of the zoo header and footer including navigation.

In the Reptile folder create a DTML Method named index_html. Give it some content more appropriate to reptiles:


<dtml-var standard_html_header>

<h1>The Reptile House</h1>

<p>Welcome to the Reptile House.</p>

<p>We are open from 6pm to midnight Monday through Friday.</p>

<dtml-var standard_html_footer>
Anonymous User - June 4, 2002 9:46 am:
 And, of course, the navigation disappears.
Anonymous User - June 16, 2002 6:29 pm:
 No, it doesn't dissapear.

 Where did you put this stuff:

 <html>
 <head><title><dtml-var title></title></head>
 <body>
 <dtml-var navigation>

 It should have gone into a DTML Method named standard_html_header.

 This is called from this new DTML Method and in turns causes the
 navigation to be included.
Anonymous User - June 24, 2002 11:57 am:
 make sure you didn't put it in your page as a couple of comment suggested above. if you put in your page
 index_html in zoo then it won't be called because it uses the "closest" index_html
Anonymous User - Aug. 9, 2002 2:28 am:
 the navigation just won`t showup in Reptile`s index_html.pls help..
Anonymous User - Aug. 9, 2002 2:37 am:
 solved it! did not create sub-sub-folders.

Now take a look at the reptile page by going to the Reptile folder and clicking the View tab.

Since the index_html method in the Reptile folder includes the standard headers and footers, the reptile page still includes your navigation system.

Click on the Snakes link on the reptile page to see what the Snakes section looks like. The snakes page looks like the Reptiles page because the Snakes folder acquires its index_html display method from the Reptiles folder.

Improving Navigation

The navigation system for the zoo works pretty well, but it has one big problem. Once you go deeper into the site you need to use your browser's back button to go back. There are no navigation links to allow you to navigate up the folder hierarchy. Let's add a navigation link to allow you to go up the hierarchy. Change the navigation method in the root folder:


<a href="..">Return to parent</a><br>

<ul>
<dtml-in expr="objectValues('Folder')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>
</dtml-in>
</ul>
Anonymous User - June 4, 2002 9:49 am:
 In the root folder? I thought we put it in the ZopeZoo folder. Or are you refering to the root of this
 project? That is a little confusing. Needs a bit of work, IMHO.
krump - Aug. 27, 2002 12:58 pm:
I made the mistake of adding a **standard_html_header** file to my ZopeZoo folder. That worked until I got to
 this part of the text, you want to modify the default **standard_html_header** at Zope's root.
Anonymous User - Sep. 13, 2002 3:23 am:
 Either/or, depends where you made your navigation object. Common sense would dictate it'd be in the ZopeZoo
 folder, but if you wanna put it in the root of your zope install, so be it.

Now browse the Zoo site to see how this new link works, as shown in Figure [5-3].

Anonymous User - June 4, 2002 9:55 am:
 Now this is interesting. I left the navigation in the standard_html_header but also put it in the
 ZopeZoo/index_html method. Now the Return to parent appears twice when I go to ZopeZoo, but when I go to
 ZopeZoo/Reptiles all I get is the return to parent. That says that the section of the navigation between the
<ul> and the </ul> is what isn't working as expected. Perhaps Objectvalues isn't returning
anything?
Anonymous User - June 16, 2002 6:35 pm:
 Are you sure you used a DTML Method, not a DTML Document for the navigation?
 Failing so could cause that problem.

 You did not mention whether the links are only missing in the Reptiles folder, or everywhere...

Improved zoo navigation controls.

Figure 5-3 Improved zoo navigation controls.

As you can see, the Return to parent link allows you to go back up from a section of the site to its parent. However some problems remain; when you are at the top level of the site you still get a Return to parent link which leads nowhere. Let's fix this by changing the navigation method to hide the parent link when you're in the ZopeZoo folder:


<dtml-if expr="_.len(PARENTS) > 2">
  <a href="..">Return to parent</a><br>
</dtml-if>

<ul>
<dtml-in expr="objectValues('Folder')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>
</dtml-in>
</ul>

Now the method tests to see if the current object has any parents before it display a link to the parent. PARENTS is a list of the current object's parents, and len is a utility function which returns the length of a list. See Appendix A for more information on DTML utility functions. Now view the site. Notice that now there is no parent link when you're viewing the main zoo page.

Anonymous User - Sep. 22, 2002 11:07 am:
 "_" is DTMLs namespace variable (where names are looked up).
 Usually this is a default, hence doesnt show up.
Anonymous User - Jan. 6, 2003 6:49 pm:
 /display/displays/  or /display/will display/

There are still some things that could be improved about the navigation system. For example, it's pretty hard to tell what section of the Zoo you're in. You've changed the reptile section, but the rest of the site all looks pretty much the same with the exception of having different navigation links. It would be nice to have each page tell you what part of the Zoo you're in.

Let's change the navigation method once again to display where you are:


<dtml-if expr="_.len(PARENTS) > 2">
  <h2><dtml-var title_or_id> Section</h2>
  <a href="..">Return to parent</a><br>
</dtml-if>

<ul>
<dtml-in expr="objectValues('Folder')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>
</dtml-in>
</ul>

Now view the site again.

Zoo page with section information.

Figure 5-4 Zoo page with section information.

As you can see in [5-4], the navigation method now tells you what section you're in along with links to go to different sections of the zoo.

Anonymous User - June 4, 2002 10:00 am:
Now I get "standard_html_header Section" from the navigation in the standard_html_header along with the one I
 added to the index_html which reads right.
Anonymous User - June 16, 2002 6:41 pm:
 This is probably caused by creating standard_html_header as DTML Document.
 It must be a DTML Method to work correctly.

Factoring out Style Sheets

Zoo pages are built by collections of methods that operate on folders. For example, the header method calls the navigation method to display navigation links on all pages. In addition to factoring out shared behavior such as navigation controls, you can use different Zope objects to factor out shared content.

Suppose you'd like to use CSS (Cascading Style Sheets ) to tailor the look and feel of the zoo site. One way to do this would be to include the CSS tags in the standard_html_header method. This way every page of the site would have the CSS information. This is a good way to reuse content, however, this is not a flexible solution since you may want a different look and feel in different parts of your site. Suppose you want the background of the snakes page to be green, while the rest of the site should have a white background. You'd have to override the standard_html_header in the Snakes folder and make it exactly the same as the normal header with the exception of the style information. This is an inflexible solution since you can't vary the CSS information without changing the entire header.

You can create a more flexible way to define CSS information by factoring it out into a separate object that the header will insert. Create a DTML Document in the ZopeZoo folder named style_sheet. Change the contents of the document to include some style information:


<style type="text/css">
h1{
  font-size: 24pt;
  font-family: sans-serif;
}
p{
  color: #220000;
}
body{
  background: #FFFFDD;
}
</style>
Anonymous User - July 3, 2002 11:04 am:
 The use of repeated inline style sheets (which is what is happening here) is not good practice! Think about
 it: every time a page is created & sent to the user, that same chunk of CSS is being sent through the
network. It's hardly going to lead to the destruction of the universe, of course - but it defeats part of the
 POINT of CSS. The great thing about CSS is that you can have it in a single file which only needs to be sent
 to a particular user ONCE. Their browser can then refer to exactly the same cache of style information for a
 selection of pages.
 It'd be a lot nicer here to tell us how to put in a consistent link to a CSS file - I mean, how to make sure
 it was "../../style/style.css" on some pages, and "style/style.css" on others, etc. [Dan]
Anonymous User - July 24, 2002 11:57 am:
Ehh, this isn't the place to lecture people on the use of external style sheets; the purpose here is to show,
 in a vivid, easy-to-grasp way, how to pull together a finished page from a mixed set of components residing
 in different places in the acquisition path. A sentence reminding people that separate, LINKed stylesheets
 are generally more efficient would be enough.
 It might also be good, in this vein, to point out that different stylehseets (or other such components) can
 be placed in sections of thr "zoo" while still falling back on the same standard_html_header throughout.
Anonymous User - Aug. 10, 2002 11:38 am:
 Besides, there is a great product for handling CSS content: http://www.zope.org/Members/haqa/ZStyleSheet
 It might looks a bit confusing on the beginning, but it is very powerful and configurable.

 Avel'ien.
Anonymous User - Sep. 21, 2002 1:51 pm:
 In reference to the comment about using external stylesheets instead of inline ones. I have done this and it
 works for me. Add a property to the root folder called stylesheet and set its value to the name of the
stylesheet stored within the root document. Then in your standard html header file add <LINK
REL="stylesheet"
HREF="<dtml-var stylesheet>" TYPE="text/css">. As long as this header is included at the top of your
pages
 you will get the css file. And the good thing is if you want to change your css file just change that one
 property on the root folder. Also, if you want subfolders to have a different css then the root folder, just
 copy the stylesheet that is in the root folder and paste it inside the subfolder. Then the documents in the
 subfolder will use the stylesheet file located in the same subfolder.

This is a CSS style sheet that defines how to display h1, p and body HTML tags. Now let's include this content into our web site by inserting it into the standard_html_header method:


<html>
<head>
<dtml-var style_sheet>
</head>
<body>
<dtml-var navigation>
Anonymous User - June 16, 2002 6:47 pm:
 The title is missing from the standard_html_header for no obvious reason.
 It was there in the initial code for standard_html_header, so it should be present here as well, IMHO.

Now, when you look at documents on your site, all of their paragraphs will be dark red, and the headers will be in a sans-serif font.

Anonymous User - June 4, 2002 10:04 am:
 Sorry, it didn't work.  I think dtmf-var is broken.
Anonymous User - June 26, 2002 11:38 pm:
 Background and foreground work fine. I changed foreground color: #220000 to color: #990000 to make it more
 distinct. Font size works too except only for headers level 1 (as the css says), which are in the Reptiles
 section. The font-family does not work and I do not know whether is's the browser or what. -VS

To change the style information in a part of the zoo site, just create a new style_sheet document and drop it into a folder. All the pages in that folder and its sub-folders will use the new style sheet.

Anonymous User - Sep. 22, 2002 11:18 am:
 STYLE: 
 just create a new _*style_sheet*_ document in the folder containing the resp. zoo part.

 folders cant be dropped

Creating a File Library

File libraries are common on web sites since many sites distribute files of some sort. The old fashioned way to create a file library is to upload your files, then create a web page that contains links to those files. With Zope you can dynamically create links to files. When you upload, change or delete files, the file library's links can change automatically.

Create a folder in the ZopeZoo folder called Files. This folder contains all of the file you want to distribute to your web visitors.

Anonymous User - Sep. 22, 2002 11:22 am:
 Previous chapters used the capitalized meta_type names _*File*_, _*Folder*_.

In the Files folder create some empty file objects with names like DogGrooming or HomeScienceExperiments, just to give you some sample data to work with. Add some descriptive titles to these files.

DTML can help you save time maintaining this library. Create an index_html DTML Method in the Files folder to list all the files in the library:


<dtml-var standard_html_header>

<h1>File Library</h1>

<ul>
<dtml-in expr="objectValues('File')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
</dtml-in>
</ul>

<dtml-var standard_html_footer>  

Now view the Files folder. You should see a list of links to the files in the Files folder as shown in [5-5].

Saman - Nov. 16, 2002 1:11 am:
 be carefull,if it dose not function instead of creating the index_html method,just copy paste the original
 one in the root folder then edit the source.
 it will work this is a bug I found that has to do something with the object ID of this file,please let me
 know if I am wrong

File library contents page.

Figure 5-5 File library contents page.

Anonymous User - June 16, 2002 6:56 pm:
 This screenshot seems outdated:

 1) The navigation is missing, for me it displays

 Files Section

 Return to parent (as a link)

 Before the content shown on the picture.

 2) The stylesheet just created is in effect, i. e. the heading is in sans-serif and the background color
 yellow.

If you add another file, Zope will dynamically adjust the file library page. You may also want to try changing the titles of the files, uploading new files, or deleting some of the files.

The file library as it stands is functional but Spartan. The library doesn't let you know when a file was created, and it doesn't let you sort the files in any way. Let's make the library a little fancier.

Anonymous User - July 18, 2002 7:29 pm:
 "Spartan" in this context is an adjective, not a verb, and thus shouldn't be capitalised.
Anonymous User - July 24, 2002 12:01 pm:
 Eh? What's adjectival use got to do with it? (And how does "Spartan" work as a verb?) I'll leave it to the
 editors to decide whether to capitalize Spartan in this case, though. It varies depending on whose style
 guide you're fond of.
Anonymous User - Aug. 25, 2002 11:08 am:
 Can we stick to the content and hold off on critiquing the author's writing style? This comment function is
 intended as a facility to get our questions answered, not to provide us with an editorial forum.
Anonymous User - Dec. 13, 2002 12:13 pm:
 Spar�tan    ( P )  Pronunciation Key  (sp�rtn)
 adj. 
 Of or relating to Sparta or its people. 
 also spartan
 Rigorously self-disciplined or self-restrained. 
 Simple, frugal, or austere: a Spartan diet; a spartan lifestyle. 
 Marked by brevity of speech; laconic. 
 Courageous in the face of pain, danger, or adversity. 

 n. 
 A citizen of Sparta. 
 One of Spartan character.

Most Zope objects have a bobobase_modification_time method that returns the time the object was last modified. We can use this method in the file library's index_html method:


<dtml-var standard_html_header>

<h1>File Library</h1>

<table>
  <tr>
    <th>File</th>
    <th>Last Modified</th>
   </tr>

<dtml-in expr="objectValues('File')">
  <tr>
     <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>
     <td><dtml-var bobobase_modification_time fmt="aCommon"></td>
  </tr>
</dtml-in>

</table>

<dtml-var standard_html_footer>  
Anonymous User - Aug. 6, 2002 9:38 am:
 Is there such a thing as 'bobobase_creation_time' ?  How would I get the time an object was created?

 The doc says 'Most Zope objects' have bobobase_modification_time - which ones?

 Where are these bobobase_* properties documented?
pdreuw - Nov. 12, 2002 12:48 pm:
 a 'bobobase_creation_time' could be easily simulated by using
    <dtml-call "manage_addProperty('creation_time',DateTime(),'string')">
 when you create the object.

 You can work with this even in your DTML-IN tags for sorting
 eg. 

 <dtml-in expr=objectValues("Folder") sort="creation_time">
 ...
 </dtml-in>

 There is no problem, if your object doesn�t have this property.

The new file library method uses an HTML table to display the files and their modification times.

Finally let's add the ability to sort this list by file name or by modification date. Change the index_html method again:


<dtml-var standard_html_header>

<h1>File Library</h1>

<table>
  <tr>
    <th><a href="&dtml-URL0;?sort=name">File</a></th>
    <th><a href="&dtml-URL0;?sort=date">Last Modified</a></th>
   </tr>

<dtml-if expr="_.has_key('sort') and sort=='date'">
  <dtml-in expr="objectValues('File')" 
           sort="bobobase_modification_time" reverse>
    <tr>
       <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>
       <td><dtml-var bobobase_modification_time fmt="aCommon"><td>
    </tr>
  </dtml-in>
<dtml-else>      
  <dtml-in expr="objectValues('File')" sort="id">
    <tr>
       <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>
       <td><dtml-var bobobase_modification_time fmt="aCommon"><td>
    </tr>
  </dtml-in>
</dtml-if>

</table>

<dtml-var standard_html_footer>  
Anonymous User - Aug. 20, 2002 9:34 am:
 Could somebody explain to me what that _.has_key()-function does so that I might be able to reuse it in
 another application?
krump - Aug. 27, 2002 1:16 pm:
 "has_key('KeyName')" is a normal Python dictionary method. Normally you would create a Python dictionary and
 then look to see if it had a particular item in it by using something like:
 DictionaryName.has_key('KeyName'). The underscore in front of the method must be something Zopish.
 Is the HTML table showing up for everyone else? That is the only part of the "File" index_html DTMLmethod
 that is not working for me.
Anonymous User - Sep. 19, 2002 1:08 am:
In the code above, the td closing tags for bobobase_modification_time are written as <td> when they
should be
 </td>. That's possibly why you're not seeing the table properly?
Anonymous User - Sep. 22, 2002 11:41 am:
 "_" is the DTML namespace variable where DTML looks up names.
 Since the bottom of this namespace contains the REQUEST object
 (which again contains, among others, the URL parameters)
 this should be better expressed as
 <dtml-if expr="REQUEST.has_key('sort') and sort=='date'">
 ("_['sort']" is not necessarily "REQUEST['sort']")

Now view the file library and click on the File and Last Modified links to sort the files. This method works with two sorting loops. One uses the in tag to sort on an object's id. The other does a reverse sort on an object's bobobase_modification_time method. The index_html method decides which loop to use by looking for the sort variable. If there is a sort variable and if it has a value of date then the files are sorted by modification time. Otherwise the files are sorted by id.

Building a Guest Book

A guest book is a common and useful web application that allows visitors to your site to leave messages. Figure [5-6] shows what the guest book you're going to write looks like.

Zoo guest book.

Figure 5-6 Zoo guest book.

Start by creating a folder called GuestBook in the root folder. Give this folder the title The Zope Zoo Guest Book. The GuestBook folder will hold the guest book entries and methods to view and add entries. The folder will hold everything the guest book needs. After the guest book is done you will be able to copy and paste it elsewhere in your site to create new guest books.

You can use Zope to create a guest book several ways, but for this example, you'll use one of the simplest. The GuestBook folder will hold a bunch of Files, one file for each guest book entry. When a new entry is added to the guest book, a new file is created in the GuestBook folder. To delete an unwanted entry, just go into the GuestBook folder and delete the unwanted file using the management interface.

Let's create a method that displays all of the entries. Call this method index_html so that it is the default view of the GuestBook folder:


<dtml-var standard_html_header>

<h2><dtml-var title_or_id></h2>

<!-- Provide a link to add a new entry, this link goes to the
addEntryForm method -->

<p>
  <a href="addEntryForm">Sign the guest book</a>
</p>

<!-- Iterate over each File in the folder starting with
the newest documents first. -->

<dtml-in expr="objectValues('File')"
         sort="bobobase_modification_time" reverse>

<!-- Display the date, author and contents of each file -->

  <p>
  <b>On <dtml-var bobobase_modification_time fmt="aCommon">, 
     <dtml-var guest_name html_quote null="Anonymous"> said:</b><br>

  <dtml-var sequence-item html_quote newline_to_br>

  <!-- Make sure we use html_quote so the users can't sneak any
  HTML onto our page -->

</p>

</dtml-in>

<dtml-var standard_html_footer>
krump - Aug. 27, 2002 1:23 pm:
 I had to set the "standard_html_header" method in the root directory back to the Zope default to get every
 thing to work. After changing it, (standard_html_header), for ZopeZoo I was getting key error's on both the
 style_sheet and the navigation variables.

This method loops over all the files in the folder and displays each one. Notice that this method assumes that each file will have a guest_name property. If that property doesn't exist or is empty, then Zope will use Anonymous as the guest name. When you create a entry file you'll have to make sure to set this property.

Next, let's create a form that your site visitors will use to add new guest book entries. In the index_html method above we already created a link to this form. In your GuestBook folder create a new DTML Method named addEntryForm:


<dtml-var standard_html_header>

<p>Type in your name and your comments and we'll add it to the
guest book.</p>

<form action="addEntryAction" method="POST">
<p> Your name: 
  <input type="text" name="guest_name" value="Anonymous">
</p>
<p> Your comments: <br>
  <textarea name="comments" rows="10" cols="60"></textarea>
</p>

<p>
  <input type="submit" value="Send Comments">
</p>  
</form>

<dtml-var standard_html_footer>

Now when you click on the Sign Guest Book link on the guest book page you'll see a form allowing you to type in your comments. This form collects the user's name and comments and submits this information to a method named addEntryAction.

Now create an addEntryAction DTML Method in the GuestBook folder to handle the form. This form will create a new entry document and return a confirmation message:


<dtml-var standard_html_header>

<dtml-call expr="addEntry(guest_name, comments)">

<h1>Thanks for signing our guest book!</h1>

<p><a href="<dtml-var URL1>">Return</a>
to the guest book.</p>

<dtml-var standard_html_footer>
Anonymous User - May 9, 2002 4:48 pm:
 URL1? Not working for me!?
Anonymous User - June 3, 2002 2:24 am:
 I've tried to send some comments to the guestbook, files of comments have been created but those comments
 didn't list out like the above pic.
Anonymous User - June 13, 2002 5:01 am:
 is it possible to send the form data straight to the form and then return to the guestbook page with the
 validated entry?
Anonymous User - July 3, 2002 11:21 am:
 To the second anonymous user who couldn't get the files to list out: I had this problem too. The
 documentation doesn't specify, but index_html should be a DTML METHOD - not a DTML DOCUMENT! What a
 ridiculous pile of
krump - Aug. 27, 2002 1:24 pm:
 In all fairness he has been using 'method' as a synonym for 'DTMLmethod' for a while. It can be easy to miss
 though.
Anonymous User - Sep. 22, 2002 11:50 am:
 Consistency: dont forget dtml tag syntax!
Anonymous User - Sep. 22, 2002 11:57 am:
 1) dtml-call was not treated in previous chapters
    (it does not insert anything in the output, only evaluates expr)
 2) how about
    <dtml-call expr="addEntry(guest_name=guest_name, comments=comments)">
    As a newbie i hav difficulty understanding the parameter passing rules.

This method creates a new entry by calling the addEntry method and returns a message letting the user know that their entry has been added.

Anonymous User - Sep. 9, 2002 8:48 am:
 pop

The last remaining piece of the puzzle is to write the script that will create a file and sets its contents and properties. We'll do this in Python since it is much clearer than doing it in DTML. Create a Python-based Script in the GuestBook folder called addEntry with parameters guest_name and comments:


## Script (Python) "addEntry"
##parameters=guest_name, comments
##
"""
Create a guest book entry.
"""
# create a unique file id
id='entry_%d' % len(context.objectIds())

# create the file
context.manage_addProduct['OFSP'].manage_addFile(id,
                                         title="", file=comments)

# add a guest_name string property
doc=getattr(context, id)
doc.manage_addProperty('guest_name', guest_name, 'string')
Anonymous User - May 22, 2002 11:06 am:
 Where does the ['OFSP'] come from?
 After digging around and doing a few searches,  I found it's a core part of
 Zope,   but no explainations.
Anonymous User - June 12, 2002 12:38 pm:
 I get an error that states:
 Error Type: TypeError
 Error Value: addEntry() takes no arguments (2 given)

 What did I do wrong?
Anonymous User - June 15, 2002 9:54 am:
 You forgot to include the parameters for the Python script in the Parameters field when pasting the script
 into a new Python Script object. You need to explicitly state what parameter your python 'function' takes
 when creating the script.
Anonymous User - Aug. 9, 2002 7:32 am:
 What`s 'OFSP'?pls include atleast single line explanations of new terms introduced in each chapter.
Anonymous User - Oct. 17, 2002 4:42 am:
 Does 'doc=getattr(context, id)' returns an instance of the file object class? What if there's another way of
 getting the instance of that object, can we use it to call the method 'doc.manage_addProperty'?
Anonymous User - Jan. 10, 2003 9:48 am:
 What is context.objectIds()? I can't find it nor in Zope API neither in Python API.

This script uses Zope API calls to create a File and to create a property on it. This script performs the same sort of actions in a script that you could do manually; it creates a file, edits it and sets a property.

Anonymous User - Sep. 22, 2002 12:08 pm:
 This script uses Zope API calls to create a File object and insert it into the scripts context Folder. The
 last two lines create a property in the File object.
 Why create the File object in the *context* and not in the *container* of the script?

The guest book is now almost finished. To use the simple guest book, just visit http://localhost:8080/GuestBook/.

Anonymous User - June 27, 2002 5:11 pm:
 Instead of the root folder I created the GuestBook several levels below. All works fine if I go thru the
 manage interface. But if I come in from "the outside" specifying full path to GuestBook, the link to
 addEntryForm points to the folder above GuestBook. If I specify the path as .../GuestBook/index_html,
 everything is copathetic again. Any clues? -VS
Anonymous User - Sep. 4, 2002 1:51 am:
 Shouldn't that be:

 http://localhost:8080/ZopeZoo/GuestBook

 for the given configuration?
Anonymous User - Sep. 4, 2002 1:53 am:
 Ack, disregard previous comment, I figured that since the GuestBook was supposed to be a feature of ZopeZoo
 that it belonged in the ZopeZoo hierarchy whereas (looking above) the example does not, silly me.

One final thing is needed to make the guest book complete. More than likely your security policy will not allow anonymous site visitors to create files. However the guest book application should be able to be used by anonymous visitors. In Chapter 7, User and Security, we'll explore this scenario more fully. The solution is to grant special permission to the addEntry method to allow it to do its work of creating a file. You can do this by setting the Proxy role of the script to Manager. This means that when the script runs it will work as though it was run by a manager regardless of who is actually running the method. To change the proxy roles go to the Proxy view of the addEntry script, as shown in [5-7].

Setting proxy roles for the addEntry script.

Figure 5-7 Setting proxy roles for the addEntry script.

Now select Manager from the list of proxy roles and click Change.

Congratulations, you've just completed a functional web application. The guest book is complete and can be copied to different sites if you want.

Anonymous User - Sep. 22, 2002 12:15 pm:
 exported and imported

Extending the Guest Book to Generate XML

All Zope objects can create XML. It's fairly easy to create XML with DTML. XML is just a way of describing information. The power of XML is that it lets you easily exchange information across the network. Here's a simple way that you could represent your guest book in XML:


<guestbook>
  <entry>
    <comments>My comments</comments>
  </entry>
  <entry>
    <comments>I like your web page</comments>
  </entry>
  <entry>
    <comments>Please no blink tags</comments>
  </entry>
</guestbook>

This XML document may not be that complex but it's easy to generate. Create a DTML Method named "entries.xml" in your guest book folder with the following contents:


<guestbook>
  <dtml-in expr="objectValues('DTML Document')">
  <entry>
    <comments><dtml-var document_src html_quote></comments>
  </entry>
  </dtml-in>
</guestbook>
Anonymous User - May 4, 2002 1:12 am:
 The guestbook entries are not 'DTML Document' type objects, but 'File' type objects in the above examples.
 Thus, I think the following codes are more suitable.
 <?xml version="1.0" encoding="EUC-KR" ?>

 <guestbook>
   <dtml-in expr="objectValues('File')">
   <entry>
    <author><dtml-var guest_name null="Anonymous"></author>
    <comments><dtml-var sequence-item html_quote></comments>
   </entry>
   </dtml-in>
 </guestbook>

As you can see, DTML is equally adept at creating XML as it is at creating HTML. Simply embed DTML tags among XML tags and you're set. The only tricky thing that you may wish to do is to set the content-type of the response to text/xml, which can be done with this DTML code:


<dtml-call expr="RESPONSE.setHeader('content-type', 'text/xml')">
Anonymous User - Aug. 31, 2002 2:33 pm:
 Where should this line be placed in the entries.xml? At the beginnning?
Anonymous User - Sep. 22, 2002 12:18 pm:
 Wherever you like

The whole point of generating XML is producing data in a format that can be understood by other systems. Therefore you will probably want to create XML in an existing format understood by the systems you want to communicate with. In the case of the guest book a reasonable format may be the RSS (Rich Site Summary) XML format. RSS is a format developed by Netscape for its my.netscape.com site, which has since gained popularity among other web logs and news sites. The Zope.org web site uses DTML to build a dynamic RSS document.

Saman - Nov. 16, 2002 1:53 am:
 could someone please explain that last sentence to me ,I cannot picture the idea
 thank you

Congratulations! You've XML-enabled your guest book in just a couple minutes. Pat yourself on the back. If you want extra credit, research RSS enough to figure out how to change entries.xml to generate RSS.

The Next Step

This chapter shows how simple web applications can be made. Zope has many more features in addition to these, but these simple examples should get you started on create well managed, complex web sites.

Anonymous User - Sep. 22, 2002 12:20 pm:
 /shows/showed/ since the chapter is over

In the next chapter, we'll see how the Zope security system lets Zope work with many different users at the same time and allows them to collaborate together on the same projects.

Previous Page Up one Level Next Page Creating Basic Zope Applications Comments On/Off Table of Contents