创建基本的Zope应用
转自: 杜文山 《快乐程序》第一辑 创建基本应用程序 参考: zope.org原文 zope.slat.org上的翻译
- Zope动物园网站的目标
- 从文件夹开始
- 特殊的文件夹对象:index_html
- 设计可导航的动物园
- 网站主导航栏
- 获取机制
- 结合组件
- 针对文件夹调用方法
- 创建与环境相关的子文件夹导航栏
- 给Header添加新元素
- 创建子文件夹的默认视图
- 加强网站的功能
- 我在哪里?
- 提炼样式表
- 在Zope“实例空间”中构建应用程序
在本章,将一步一步的讲解如何构建简单的Web应用程序。在这个过程中,将涉及到常用的Zope核心概念。使用到的对象包括:文件夹、Script(Python)和页面模板。我们将通过使用这几种对象创建一个简单的网站,名称是:Zope动物园。
我们将以“实例空间”的方式开发这个网站。本章的后边将讲解“实例空间”,但目前,只要知道它是一种最容易最快速的方式就可以了,这是因为全部的例子都可以通过web浏览器来完成。
1. Zope动物园网站的目标
首先我们必须清楚要完成的目标。这个应用程序的主要目标是为Zope动物园创建一个Web网站,并且网站要容易使用和管理。基本的要求是:
- 要让Web用户能够轻松的周游站点,就好像他们正在步行走过一个真实的动物园。
- 外观要容易调整和管理,比如对于层叠样式表(CSS)。
- 网站要进行良好的设计和组织,以便于将来进行更改。
- 要利用Zope的动态特性,实现内容的自动更新。
2. 从文件夹开始
Zope当中的文件夹对象提供了一种很直观的内容组织方式。我们可以从创建文件夹开始。这些文件夹用来存放各种对象。
举个例子,我们可以创建一个名为“Invoices”的文件夹,用来存放订单。这个文件夹中可以包含用于处理订单的逻辑对象或方法,也可以存放订单数据。整个目录就形成了一个简单的应用程序。
下面我们将为动物园网站创建文件夹,用于存放所有相关的对象。
2.1. 第一步:创建文件夹
首先启动Zope,通过浏览器登录进入管理界面,然后:
- 进入根目录
- 通过添加列表创建一个新文件夹
- 指定id为 ZopeZoo?
- 选中“Create public interface”
- 点击 Add 按钮。
3. 特殊的文件夹对象:index_html
因为我们选择了“Create public interface”选项,因此Zope还会在创建文件夹的同时创建一个页面模板对象:index_html。
index_html是ZopeZoo文件夹中默认对象,当Web用户访问这个目录时就调用index_html。这就如同是Apache服务器中默认的文件是index.html一样。
index_html是文件夹对象的默认视图。我们可以通过多种方式来查看ZopeZoo文件夹:
- 点击index_html对象的“Test”标签
- 点击文件夹ZopeZoo的“View”标签
- 浏览器中直接输入网址:http://localhost:8080/ZopeZoo/index_html
- 浏览器中直接输入网址:http://localhost:8080/ZopeZoo/
4. 设计可导航的动物园
为了实现能够轻松浏览网站的目的,需要在网站的页面中加入导航的功能。换句话说,就是在网站中的每个页面里都要显示一段相似的链接,帮助用户访问站点中的每个部分。
并且还要确保导航链接都是正确的,而不管站点结构如何变化。解决的方法是设计合理的网站结构,然后创建用来在导航链接中显示结构的Zope方法。
首先让我们定义站点的结构。假设动物园中有三类动物。通过添加文件夹来组织站点。
4.1. 第二步:创建网站结构
(注意,不要在这一步中添加index_html对象,即不用选择“Create public interface”)- 进入ZopeZoo文件夹,创建三个子文件夹,id分别为:Reptiles, Mammals and Fish。
- 在Mammals文件夹中添加一个名为Whales的文件夹。
- 在Reptiles中创建两个文件夹:Lizards 和 Snakes。
| 动物园文件夹结构 |
现在,我们假设,要浏览动物园网站,永辉会从默认的视图(index_html)开始。可以称这个页面为首页。通过首页,用户应该可以选择一个链接,进入下级文件夹,从而访问想看到的动物。
5. 网站主导航栏
首先,让我们创建导航方法,用来显示网站的主导航栏,也就是那些可以访问站点主栏目(Fish, Mammals, and Reptiles)的链接。站点中的每个页面都调用这个方法。并且这个方法会动态创建下级文件夹的链接。
导航的方法采用页面模板(ZPT)。让我们来创建这个模板,并仔细看看TAL的使用方式。
5.1. 第三步:创建网站主导航方法
- 进入ZopeZoo文件夹。
- 从添加列表中选择页面模板
- 输入id: nav_main
- 点击 Add and Edit
- 编辑代码如下:
<a href="HOME_URL" tal:attributes="href container/absolute_url"
tal:content="container/title_or_id">HOME TITLE OR ID</a>
<span tal:repeat="foldy container/objectValues" tal:omit-tag="">
| <a href="URL" tal:attributes="href foldy/absolute_url"
tal:content="foldy/title_or_id">TITLE OR ID</a>
</span>
| 主导航模板 |
此时会发现,导航的作用生效了,但同时发现,index_html和nav_main也列了出来。 我们不想显示所有的对象,只希望显示文件夹对象。因此还需要对代码进行修改。
5.2. 第四步:排除非文件夹对象
- 返回nav_main代码部分,然后找到span部分,把代码改成:
<span tal:repeat="foldy
python:container.objectValues(['Folder'])" tal:omit-tag=""> - 点击 Save Changes.
6. 获取机制
获取机制可以用来共享属性。比如,我们这个例子中ZopeZoo文件夹的index_html属性。 关于获取机制,核心的思想就是如果某个对象缺少某个属性,Zope会自动向上级目录中搜索这个属性,直到找到为止。 在我们这个例子中,如果animal目录中不能找到index_html,Zope会自动尝试向上级目录中查找。直到搜索到ZopeZoo文件夹。 假设ZopeZoo中也没有index_html,那么就继续往上查找,直到根文件夹,如果还没有就会提示错误信息。如果站点中存在多个index_html,则会采用最近的一个。 比如,对于Web请求: http://localhost:8080/ZopeZoo/Mammals/,Zope会先搜索Mammals文件夹中的index_html,如果找到了就返回这个index_html。
7. 结合组件
我们将继续创建两个新的Zope页面模板。第一个是页眉模板,它用来处理导航,放在每个页面的上部。然后创建一个与正文相关的页面模板,用来显示正文内容。 然后,把这些组件结合进入index_html,形成基本的网站框架。
7.1. 第五步:创建几个组件
- 返回到ZopeZoo文件夹。
- 添加两个页面模板,id分别为header和body_content。
- 编辑header代码如下:
<div id="header">
<div id="nav-main" tal:content="here/nav_main">
MAIN NAVIGATION
</div>
</div> - 点击 Save Changes
| 页面的HTML代码 |
很明显,这不是我们想要的结果。Zope会自动把HTML代码转化成可显示的字符。但我们需要的是能够在其它页面中调用并显示的HTML。让我们继续解决这个问题。
7.2. 第六步:指定HTML的构成,而不是显示HTML代码
- 返回到header模板的代码部分,在tal:content语句中插入 structure 关键字,代码如下:
<div id="header">
<div id="nav-main" tal:content="structure here/nav_main">
MAIN NAVIGATION
</div>
</div> - 保存更改
| 新的页眉 |
接下来,让我们来编辑body_content模板,需要让body_content成为 index_html 的一部分。
7.3. 第七步:准备 body_content 模板
- 返回到ZopeZoo文件夹,点击body_content模板。
- 编辑代码部分,只保留<body>和</body>之间的代码(不包括<body>和</body>)。
- 保存
7.4. 第八步:组织默认的视图
- 返回到ZopeZoo文件夹,点击index_html
- 用以下代码替换原有的代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title tal:content="here/title_or_id">TITLE</title>
</head>
<body>
<span tal:replace="structure here/header">DUMMY HEADER</span>
<span tal:replace="structure here/body_content">BODY</span>
</body>
</html> - 点击 Save Changes
http://localhost:8080/ZopeZoo/(如果Zope没有安装在本机中,需要localhost换成网址)可以看到如下结果:
| 默认的视图 |
现在可以看到一个比较完整的网站框架,它有导航栏,并且可以动态的创建链接。
点击链接时,通过 http://localhost:8080/ZopeZoo/Reptiles/ ,Web服务器接收到请求。Zope返回Reptiles文件夹默认的视图,即index_html。
由于Reptiles文件夹中没有index_html,于是向上搜索index_html。然后调用header方法。header又调用nav_main。最后index_html又调用body_content,生成完整的index_html页面。
注意,尽管index_html位于ZopeZoo文件夹中,但是却能够针对Reptiles对象返回相应的信息。这是因为index_html是针对Reptiles对象进行调用的。
8. 针对文件夹调用方法
Zope中的获取机制与对象调用时所处的环境密切相关,是Zope中的一个强大特性。因此通过URL加上要调用的方法的id,就可以对任何对象调用方法。在上面的例子中,还没有充分利用这一特性,我们只是调用了默认的方法index_html。
比如,对于前边提过的URL:http://localhost:8080/Invoices/addInvoice ,其中Invoices是一个文件夹对象。这个URL表示针对Invoices调用addInvoice方法。
这个功能是Zope中一个通用的特性。实际上,除了文件夹对象,还可以对很多对象调用方法。详细方法可参考“高级Zope脚本”一章。
另外,还可以通过URL传递参数。例如:http://localhost:8080/Invoices/editInvoice?invoice_number=42。这个URL把参数 invoice_number=42 传递给Invoices文件夹的editInvoice方法。通过这种方式就可以编辑序号为42的订单。
9. 创建与环境相关的子文件夹导航栏
接下来,我们将加强导航栏。我们将在页眉部分增加一个子文件夹导航部分,放在主栏目导航链接的后边。
在nav_main对象中定义的主栏目导航栏保持不变。我们将创建一个导航组件,它会根据用户所处的位置进行变化,显示出所有的子文件夹,从而可以充分显示网站的逻辑结构。
9.1. 第九步:创建子文件夹导航方法
- 进入ZopeZoo文件夹
- 加一个id为nav_subfolder的页面模板
- 点击Add and Edit
- 用以下代码替换原来的代码:
<ul>
<li tal:repeat="foldo python:here.objectValues(Folder)">
<a href="HREF" tal:attributes="href foldo/absolute_url"
tal:content="foldo/title_or_id">TITLE OR ID</a>
</li>
</ul> - 保存
| 子文件夹导航 |
其中的代码和以前看到的很相似,不同之处在于tal:repeat语句中使用了"here",而不是"container"。这是关键之处,体现了获取机制。 TAL中的container表示的是模板所处的文件夹,而here表示的是模板所应用的对象。使用Test标签测试这段代码时,结果是一样的,这是因为container和here都是同一个对象:ZopeZoo文件夹。 要看到here所起的作用,我们需要针对另外一个对象调用这个模板。比如,打开一个新的浏览器窗口,然后访问以下URL:
http://localhost:8080/ZopeZoo/Reptiles/nav_subfolder你会看到文件夹Reptiles中的子文件夹列表,如下图所示:
| 对Reptiles调用nav_subfolder |
同样,如果我们针对Mammals文件夹调用nav_subfolder,就会显示其子文件夹的链接。这个方法可以针对任何对象进行调用(只有文件夹能够显示结果)。由于nav_subfolder位于站点的ZopeZoo文件夹中,因此所有子文件夹都可以调用它。
10. 给Header添加新元素
为了能够在站点中的每个页面中都可以调用nav_subfolder,需要在header中调用它。当然也可以直接在index_html中调用它,但是放在header中会更好些。
当站点中有多个index_html时,这种方式特别有用,这是因为header是一样的,修改了header,站点中所有页面都会自动变化。当然,你完全可以根据需要进行调整。
10.1. 第十步:结合子文件夹导航栏
- 进入ZopeZoo文件夹,点击header页面模板。
- 修改代码如下:
<div id="header">
<div id="nav-main" tal:content="structure here/nav_main">
MAIN NAVIGATION
</div>
<div id="nav-subfolder" tal:content="structure here/nav_subfolder">
SUBFOLDER NAVIGATION
</div>
</div> - 保存
11. 创建子文件夹的默认视图
我们可以看到,文件夹对象可以从上级文件夹中获取index_html。目前为止,调用的都是ZopeZoo文件夹中的index_html。 如果某些文件夹需要调用不同的默认视图,只需要在这些文件夹中创建新的index_html就可以了。比如,可以在Reptiles文件夹中创建一个新的index_html。新的默认视图对所有的子文件夹(Snakes和Lizards)都会生效。 我们继续使用ZopeZoo文件夹中的index_html,不创建新的index_html。我们通过使用body_content来为每个文件夹创建不同的内容。 通过这种方式可以实现内容与界面部分的分离。我们只需要在每个文件夹中添加一个body_content就可以了。
11.1. 第十一步:定制默认视图
- 通过管理界面,进入Reptiles文件夹。
- 添加一个id为body_content的页面模板
- 输入以下代码:
<h1>The Reptile House</h1>
<p>We are open from 6pm to midnight Monday through Friday.</p>
<h2>Interesting reptile fact:</h2>
<p>The shape of a reptile's pupil indicates whether the animal
is active at night or during the day. Most reptiles active at
night have slit-like pupils that can be closed almost
completely in bright light. Reptiles active in daytime have
round pupils.
</p>
<p>For more interesting facts, visit
<a href="http://www2.worldbook.com/features/reptiles/html/facts.html">
this World Book site</a>.
</p> - 保存
12. 加强网站的功能
现在,我们的导航系统已经可以工作了,但是它有一个问题。用户要是进入站点栏目,比如从Mammals 进入 Whales,则需要使用浏览器的“返回”按钮来返回到上一级。我们的导航栏中还没有提供返回到上级的链接。
接下来,让我们给nav_subfolder添加一个“返回到上级”的链接。
12.1. 第十二步:添加一个“Return to Parent”链接
- 进入ZopeZoo文件夹的nav_subfolder模板
- 在代码的开始部分加入新的一行后,如下:
<p><a href="..">Return to parent</a></p>
<ul>
<li tal:repeat="foldo python:here.objectValues(Folder)">
<a href="HREF" tal:attributes="href foldo/absolute_url"
tal:content="foldo/title_or_id">TITLE OR ID</a>
</li>
</ul> - 保存
12.2. 第十三步:修改“Parent Link”模板代码
- 在Zope管理界面中,进入到nav_subfolder页面模板
- 修改代码如下:
<p tal:condition="python:here.id != 'ZopeZoo'">
<a href="..">Return to parent</a></p>
<ul>
<li tal:repeat="foldo python:here.objectValues(Folder)">
<a href="HREF" tal:attributes="href foldo/absolute_url"
tal:content="foldo/title_or_id">TITLE OR ID</a>
</li>
</ul> - 保存
13. 我在哪里?
在我们的例子中,还存在一个不方便的地方,就是当在Reptiles中添加body_content以后,失去了一些信息。比如当用户浏览Lizards Snakes文件夹时,很难判断出所处的位置。
位于ZopeZoo文件夹中的body_content方法包含了显示用户当前位置的代码,即用 here/title_or_id 显示当前对象的标题或id。 接下来,我们把这个功能放入到header对象中,这样就可以让所有页面都具有这个功能。
13.1. 第十四步:添加“You Are Here”元素
- 进入ZopeZoo文件夹中的header页面模板
- 添加<h2>元素,代码修改成:
<div id="header">
<div id="nav-main" tal:content="structure here/nav_main">
MAIN NAVIGATION
</div>
<div id="nav-subfolder" tal:content="structure
here/nav_subfolder">
SUBFOLDER NAVIGATION
</div>
<h2>You are in the
<span tal:replace="here/title_or_id">TITLE_ID</span>
section.
</h2>
</div> - 保存
14. 提炼样式表
Zope中鼓励把可以重复使用的部分提炼出来。前面已经看到,我们已经把导航部分提炼了出来,形成了header。通过这样一种方式就可以实现共享。 在HTML中,可以通过层叠样式表(CSS)规定网页外观,比如颜色、字体等等。CSS可以很方便的调整页面的外观。 所以,提炼出样式表信息,就可以帮助我们方便的管理网站的外观。通过在不同的文件夹中编排CSS文件,就可以对网站中不同的部分实现不同的外观。 CSS文件是一种文本文件。下面,通过Zope文件对象给我们的网站添加样式表。
14.1. 第十五步:创建网站样式表
- 进入ZopeZoo文件夹。
- 添加一个id为style_sheet的File对象。
- 点击style_sheet,进入编辑状态。
- 修改文件类型为:text/css
- 编辑代码如下:
body {
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
background-color: #F0FFF0;
}
h2 {
color: Green;
}
#header {
padding: 1em;
background-color: #90EE90;
font-size: smaller;
}
#header h2 {
font-style: italic;
font-size: 12pt;
}
#nav-main {
margin-bottom: 1em;
}
#nav-subfolder {
font-weight: bold;
} - 保存更改
14.2. 第十六步:调用样式表
- 进入ZopeZoo文件夹,点击index_html。
- 在<head>部分插入样式表,即修改代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title tal:content="here/title_or_id">TITLE</title>
<style type="text/css">
<!--
@import url(style_sheet);
-->
</style>
</head>
<body>
<span tal:replace="structure here/header">DUMMY HEADER</span>
<span tal:replace="structure here/body_content">BODY</span>
</body>
</html> - 保存修改
| 美化后的动物园 |
如果要更改网站中其它部分的外观,可以利用获取机制,在文件夹中增加一个style_sheet就可以了。这个文件夹和子文件夹中都会调用这个style_sheet。
15. 在Zope“实例空间”中构建应用程序
要开发一个Web应用程序,在Zope中有多种方式。最简单快速的方式就是我们在上面采用的方式,即在实例空间中构建。要理解“实例空间”这个概念,需要再次提及面向对象的概念。 实例空间相当于Zope的根文件夹。使用web浏览器,我们就可以在实例空间中通过管理界面来查看和控制对象。 实例空间中所有的对象组件都是Zope类的实例。我们通过添加各种实例对象,就可以简单的构建应用程序。 如下图所示,显示了一个管理界面,并且选择了添加列表。
| Zope管理界面中的添加列表 |
添加列表中的每个对象都表示了Zope中已经定义好的类。当我们选择了一个类,就会提示我们输入创建类的实例所需的信息。然后,Zope就会使用输入的信息在当前的位置创建新的实例。这个实例直到被删除才会消失。 比如,文件夹(Folder)类就是由Zope公司的工程师编写的。所有在管理界面中显示的文件夹对象都是文件夹类的实例。由于每个对象都是某种类的实例,因此我们使用“实例空间”这个概念来表示ZODB中所有的对象。 要在实例空间中构建应用程序,就需要通过管理界面创建Zope类的实例。我们通过调整实例,就可以让它们完成特定的功能,然后把它们结合到一起,就创建了Zope应用程序。
15.1. 实例空间应用程序与产品
除了通过在实例空间中构建Zope应用程序,还可以通过开发“产品”来构建。通过产品的方式,可以在添加列表中显示出来,从而可以通过新对象来扩展Zope。另外,产品应用程序容易分发给其他人,并且可以创建更为实用的对象。
在“扩展Zope”一章中,集中讲解了如何创建产品。 [Folder])">
