Personal tools
You are here: Home Zope Zope宝典 创建基本的Zope应用
Document Actions

创建基本的Zope应用

by 潘俊勇 last modified 2005-12-14 14:27

转自: 杜文山 《快乐程序》第一辑 创建基本应用程序 参考: zope.org原文 zope.slat.org上的翻译


  1. Zope动物园网站的目标
  2. 从文件夹开始
  3. 特殊的文件夹对象:index_html
  4. 设计可导航的动物园
  5. 网站主导航栏
  6. 获取机制
  7. 结合组件
  8. 针对文件夹调用方法
  9. 创建与环境相关的子文件夹导航栏
  10. 给Header添加新元素
  11. 创建子文件夹的默认视图
  12. 加强网站的功能
  13. 我在哪里?
  14. 提炼样式表
  15. 在Zope“实例空间”中构建应用程序

  在本章,将一步一步的讲解如何构建简单的Web应用程序。在这个过程中,将涉及到常用的Zope核心概念。使用到的对象包括:文件夹、Script(Python)和页面模板。我们将通过使用这几种对象创建一个简单的网站,名称是:Zope动物园。

  我们将以“实例空间”的方式开发这个网站。本章的后边将讲解“实例空间”,但目前,只要知道它是一种最容易最快速的方式就可以了,这是因为全部的例子都可以通过web浏览器来完成。

1. Zope动物园网站的目标

  首先我们必须清楚要完成的目标。这个应用程序的主要目标是为Zope动物园创建一个Web网站,并且网站要容易使用和管理。基本的要求是:

  • 要让Web用户能够轻松的周游站点,就好像他们正在步行走过一个真实的动物园。
  • 外观要容易调整和管理,比如对于层叠样式表(CSS)。
  • 网站要进行良好的设计和组织,以便于将来进行更改。
  • 要利用Zope的动态特性,实现内容的自动更新。

2. 从文件夹开始

  Zope当中的文件夹对象提供了一种很直观的内容组织方式。我们可以从创建文件夹开始。这些文件夹用来存放各种对象。

  举个例子,我们可以创建一个名为“Invoices”的文件夹,用来存放订单。这个文件夹中可以包含用于处理订单的逻辑对象或方法,也可以存放订单数据。整个目录就形成了一个简单的应用程序。

  下面我们将为动物园网站创建文件夹,用于存放所有相关的对象。

2.1. 第一步:创建文件夹

  首先启动Zope,通过浏览器登录进入管理界面,然后:

  1. 进入根目录
  2. 通过添加列表创建一个新文件夹
  3. 指定id为 ZopeZoo?
  4. 选中“Create public interface”
  5. 点击 Add 按钮。

3. 特殊的文件夹对象:index_html

  因为我们选择了“Create public interface”选项,因此Zope还会在创建文件夹的同时创建一个页面模板对象:index_html。

  index_html是ZopeZoo文件夹中默认对象,当Web用户访问这个目录时就调用index_html。这就如同是Apache服务器中默认的文件是index.html一样。

  index_html是文件夹对象的默认视图。我们可以通过多种方式来查看ZopeZoo文件夹:

  1. 点击index_html对象的“Test”标签
  2. 点击文件夹ZopeZoo的“View”标签
  3. 浏览器中直接输入网址:http://localhost:8080/ZopeZoo/index_html
  4. 浏览器中直接输入网址:http://localhost:8080/ZopeZoo/
   对象index_html可以是页面模板、DTML方法、Script对象或者其它任何一种可以通过URL可以访问的对象。这个对象应当返回HTML或 其它数据,比如:XML或文本等等。从面向对象的角度来说,index_html不仅是文件夹中的一个对象,同时还是文件夹的一个方法或属性。

4. 设计可导航的动物园

  为了实现能够轻松浏览网站的目的,需要在网站的页面中加入导航的功能。换句话说,就是在网站中的每个页面里都要显示一段相似的链接,帮助用户访问站点中的每个部分。

  并且还要确保导航链接都是正确的,而不管站点结构如何变化。解决的方法是设计合理的网站结构,然后创建用来在导航链接中显示结构的Zope方法。

首先让我们定义站点的结构。假设动物园中有三类动物。通过添加文件夹来组织站点。

4.1. 第二步:创建网站结构

  (注意,不要在这一步中添加index_html对象,即不用选择“Create public interface”)

  1. 进入ZopeZoo文件夹,创建三个子文件夹,id分别为:Reptiles, Mammals and Fish。
  2. 在Mammals文件夹中添加一个名为Whales的文件夹。
  3. 在Reptiles中创建两个文件夹:Lizards 和 Snakes。
  通过管理界面中的导航框架,可以看到文件夹ZopeZoo的结构。如果看不到,刷新页面。通过点击“+”号图标可以打开文件夹。如下图所示:

动物园文件夹结构

  现在,我们假设,要浏览动物园网站,永辉会从默认的视图(index_html)开始。可以称这个页面为首页。通过首页,用户应该可以选择一个链接,进入下级文件夹,从而访问想看到的动物。

5. 网站主导航栏

  首先,让我们创建导航方法,用来显示网站的主导航栏,也就是那些可以访问站点主栏目(Fish, Mammals, and Reptiles)的链接。站点中的每个页面都调用这个方法。并且这个方法会动态创建下级文件夹的链接。

导航的方法采用页面模板(ZPT)。让我们来创建这个模板,并仔细看看TAL的使用方式。

5.1. 第三步:创建网站主导航方法

  1. 进入ZopeZoo文件夹。
  2. 从添加列表中选择页面模板
  3. 输入id: nav_main
  4. 点击 Add and Edit
  5. 编辑代码如下:
              <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>
  代码前两行,用于创建和模板容器的链接。 剩下的代码用于循环处理当前容器中存在的对象。符号“|”用来区分显示。让我们仔细看看代码部分。 在<span>部分,tal:repeat 语句定义了专用变量foldy,用来表示容器中的对象序列。整个<span>部分进行循环处理。 但在结果中,<span>符号是没有用的,不需要显示,因此,加入了 tal:omit-tag 属性。这样在模板运行时就会去掉这个符号。 每个循环之间用“|”符号格开,这样就显得比较整齐。链接部分和前两行一样。 点击“Save Changes”按钮,然后点击工作区中的Test标签。结果如下:

主导航模板

  此时会发现,导航的作用生效了,但同时发现,index_html和nav_main也列了出来。 我们不想显示所有的对象,只希望显示文件夹对象。因此还需要对代码进行修改。

5.2. 第四步:排除非文件夹对象

  1. 返回nav_main代码部分,然后找到span部分,把代码改成:
              <span tal:repeat="foldy
    python:container.objectValues(['Folder'])" tal:omit-tag="">
  2. 点击 Save Changes.
  然后再进行测试,会发现只显示文件夹对象了。这样就形成了主导航栏。 如果文件夹中没有index_html,则会通过获取机制来取得上级目录中的index_html对象。

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. 第五步:创建几个组件

  1. 返回到ZopeZoo文件夹。
  2. 添加两个页面模板,id分别为header和body_content。
  3. 编辑header代码如下:
              <div id="header">
    <div id="nav-main" tal:content="here/nav_main">
    MAIN NAVIGATION
    </div>
    </div>
  4. 点击 Save Changes
  <div>符号中通过使用id属性,可以使用层叠样式表来更改界面。点击 Test 标签,可以看到以下一些HTML代码:

页面的HTML代码

  很明显,这不是我们想要的结果。Zope会自动把HTML代码转化成可显示的字符。但我们需要的是能够在其它页面中调用并显示的HTML。让我们继续解决这个问题。

7.2. 第六步:指定HTML的构成,而不是显示HTML代码

  1. 返回到header模板的代码部分,在tal:content语句中插入 structure 关键字,代码如下:
              <div id="header">
    <div id="nav-main" tal:content="structure here/nav_main">
    MAIN NAVIGATION
    </div>
    </div>
  2. 保存更改
  然后,进行测试,就会发现结果正常了,显示的内容和直接调用nav_main模板差不多。如下图所示:

新的页眉

  接下来,让我们来编辑body_content模板,需要让body_content成为 index_html 的一部分。

7.3. 第七步:准备 body_content 模板

  1. 返回到ZopeZoo文件夹,点击body_content模板。
  2. 编辑代码部分,只保留<body>和</body>之间的代码(不包括<body>和</body>)。
  3. 保存
  接下来,让我们把这些组件组织到 index_html 中,这样就可以创建默认的视图。

7.4. 第八步:组织默认的视图

  1. 返回到ZopeZoo文件夹,点击index_html
  2. 用以下代码替换原有的代码:
              <!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>
  3. 点击 Save Changes
  可以看到,这个index_html是通过指定两个组件来构成的,即header和body_content。通过在浏览器中输入以下网址,可以进行测试:
        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. 第九步:创建子文件夹导航方法

  1. 进入ZopeZoo文件夹
  2. 加一个id为nav_subfolder的页面模板
  3. 点击Add and Edit
  4. 用以下代码替换原来的代码:
              <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>
  5. 保存
  点击Test标签,会看到列出了三个链接。如下所示:

子文件夹导航

  其中的代码和以前看到的很相似,不同之处在于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. 第十步:结合子文件夹导航栏

  1. 进入ZopeZoo文件夹,点击header页面模板。
  2. 修改代码如下:
              <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>
  3. 保存
  在浏览器中输入 http://localhost:8080/ZopeZoo/ ,进行测试,就会看到新出现的子文件夹导航栏。

11. 创建子文件夹的默认视图

  我们可以看到,文件夹对象可以从上级文件夹中获取index_html。目前为止,调用的都是ZopeZoo文件夹中的index_html。 如果某些文件夹需要调用不同的默认视图,只需要在这些文件夹中创建新的index_html就可以了。比如,可以在Reptiles文件夹中创建一个新的index_html。新的默认视图对所有的子文件夹(Snakes和Lizards)都会生效。 我们继续使用ZopeZoo文件夹中的index_html,不创建新的index_html。我们通过使用body_content来为每个文件夹创建不同的内容。 通过这种方式可以实现内容与界面部分的分离。我们只需要在每个文件夹中添加一个body_content就可以了。

11.1. 第十一步:定制默认视图

  1. 通过管理界面,进入Reptiles文件夹。
  2. 添加一个id为body_content的页面模板
  3. 输入以下代码:
              <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>
  4. 保存
  如果点击Test标签,就会看到以上的页面。要完整的看结果,可以输入网址:http://localhost:8080/ZopeZoo/Reptiles/ ,就会看到完整的结果。 通过这样一种方式,就可以实现调用同一个index_html,但显示的是对应文件夹中的数据内容。 如果点击Snakes链接,显示的页面内容是和Reptiles一样的。这是因为Snakes位于Reptiles文件夹中,使用的是Reptiles中的body_content。 另外,还会发现没有了子文件夹导航栏。这是因为Snakes目录中没有子文件夹。

12. 加强网站的功能

  现在,我们的导航系统已经可以工作了,但是它有一个问题。用户要是进入站点栏目,比如从Mammals 进入 Whales,则需要使用浏览器的“返回”按钮来返回到上一级。我们的导航栏中还没有提供返回到上级的链接。

  接下来,让我们给nav_subfolder添加一个“返回到上级”的链接。

12.1. 第十二步:添加一个“Return to Parent”链接

  1. 进入ZopeZoo文件夹的nav_subfolder模板
  2. 在代码的开始部分加入新的一行后,如下:
              <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>
  3. 保存
  这样编辑完以后,当再次访问站点时,就会很方便的返回上级文件夹。 但是,又发现另外一个问题,就是当用户位于站点顶级文件夹(就是ZopeZoo)时,仍然存在返回上级的链接。这个链接是不需要的。我们可以通过添加一个判断语句来弥补这个缺点。

12.2. 第十三步:修改“Parent Link”模板代码

  1. 在Zope管理界面中,进入到nav_subfolder页面模板
  2. 修改代码如下:
              <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>
  3. 保存
  以上代码中是通过在TAL中提供一个python判断来实现的。如果here对象的id不是"ZopeZoo?",则Python表达式的值为真,则显示链接。如果值为假,则忽略显示链接。 在这个例子中,如过here.id等于"ZopeZoo?",Python表达式的值为假,那么就会把链接去掉。

13. 我在哪里?

  在我们的例子中,还存在一个不方便的地方,就是当在Reptiles中添加body_content以后,失去了一些信息。比如当用户浏览Lizards Snakes文件夹时,很难判断出所处的位置。

  位于ZopeZoo文件夹中的body_content方法包含了显示用户当前位置的代码,即用 here/title_or_id 显示当前对象的标题或id。 接下来,我们把这个功能放入到header对象中,这样就可以让所有页面都具有这个功能。

13.1. 第十四步:添加“You Are Here”元素

  1. 进入ZopeZoo文件夹中的header页面模板
  2. 添加<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>
  3. 保存
  现在我们的站点就可以显示所处位置信息了。

14. 提炼样式表

  Zope中鼓励把可以重复使用的部分提炼出来。前面已经看到,我们已经把导航部分提炼了出来,形成了header。通过这样一种方式就可以实现共享。 在HTML中,可以通过层叠样式表(CSS)规定网页外观,比如颜色、字体等等。CSS可以很方便的调整页面的外观。 所以,提炼出样式表信息,就可以帮助我们方便的管理网站的外观。通过在不同的文件夹中编排CSS文件,就可以对网站中不同的部分实现不同的外观。 CSS文件是一种文本文件。下面,通过Zope文件对象给我们的网站添加样式表。

14.1. 第十五步:创建网站样式表

  1. 进入ZopeZoo文件夹。
  2. 添加一个id为style_sheet的File对象。
  3. 点击style_sheet,进入编辑状态。
  4. 修改文件类型为:text/css
  5. 编辑代码如下:
              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;
    }
  6. 保存更改
  样式表规定了如何显示<body>和<h2>元素,以及模板中的<div>部分。现在需要让web页面引用这个样式表。HTML中,在<head>部分调用样式表。

14.2. 第十六步:调用样式表

  1. 进入ZopeZoo文件夹,点击index_html。
  2. 在<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>
  3. 保存修改
  点击index_html的Test标签进行测试,就会看到网站外观变得好看多了。如下图所示:

美化后的动物园

  如果要更改网站中其它部分的外观,可以利用获取机制,在文件夹中增加一个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])">


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: