Personal tools
You are here: Home Zope Zope宝典 高级页面模板2
Document Actions

高级页面模板2

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

第九章 高级页面模板

翻译: 杜文山 / 邮件: zope@dohao.org

如有不妥,欢迎批评指正

+9.2 表单处理

在DTML里,你可以使用一种“form/action对”的模式来处理表单。一个form/action对由两个方法或文档组成: 一个当中包含收集用户输入信息的表单,另外一个包含可以处理输入并返回结果的行为。表单调用行为。有关form/action模式方面更多信息请见第四章“用DTML处理动态内容”。

Zope页面模板对于form/action模式不能很好的工作,这是由于它假设输入处理和回应是有同一对象来完成的。对于页面模板,不用form/action模式,你应该使用form/action/response模式。Form和response应该为页面模板,action应该为一个脚本。表单模板收集输入,然后调用回应脚本。回应脚本应该处理输入,然后返回一个回应模板。这种模式比form/action模式更为灵活,这是由于它允许脚本返回任意数量不同类型的回应对象。

例如,以下是一个表单模板的一部分:

          ...
          <form action="action">
            <input type="text" name="name">
            <input type="text" name="age:int">
            <input type="submit">
          </form>
          ...

这个表单应该用以下脚本处理:

          ## Script (Python) "action"
          ##parameters=name, age
          ##
          container.addPerson(name, age)
          return container.responseTemplate()

这个脚本调用一个方法来处理输入,然后返回另外一个模板,即回应。你可以通过从Python调用模板来执行一个页面模板。回应模板一般包含表单被正确处理的确认信息。

行为脚本可以完成各种任务。它可以检验输入,处理错误,发送邮件,以及其它任务等。以下是一个简单的用脚本确认输入的例子:

          ## Script (Python) "action"
          ##
          if not context.validateData(request):
              # if there's a problem return the form page template
              # along with an error message
              return context.formTemplate(error_message='Invalid data')

          # otherwise return the thanks page
          return context.responseTemplate()

这个脚本检验表单输入,并返回表单模板,如果存在问题就带有一个错误消息。你可以用关键字参数给页面模板传递额外的信息。关键字参数通过内建变量选项的形式存在。因此这个例子里的表单模板可能会包括这样一部分:

          <b tal:condition="options/error_message | nothing"
             tal:content="options/error_message">
            Error message goes here.
          </b>  

这个例子显示了如何通过关键字参数给模板传递一个要显示的错误消息。

根据你的应用程序的不同,你可以选择让用户指向一个回应页面模板,而不是直接返回它。这样就形成了两次网络活动,但它的用途在于更改了显示在用户的浏览器中的URL,而不是回应脚本的URL。

如果你坚持要采用原来的方式,你可以用页面模板创建一个form-action对。但只有当你不关心错误处理时,你才能这样做,并且回应应该总是一样,不管用户提交了什么。由于页面模板没有象dtml-call那样的等同语句,你可以使用任何一种方式来调用输入处理方法,而不用插入结果。例如::

这个例子调用了processInputs方法,并且把结果分配给unused变量.

+9.3 表达式

你已经用过了页面模板表达式。表达式给模板语句提供值。例如,路径表达式以赋予路径的方式描述了对象,比如request/form/age, 或者 user/getUserName这样的路径。在本节,你将学习各种类型的表达式,以及变量。

+9.3.1内建变量

变量就是你在表达式里可以用的名称。你已经在一些例子里看到内建变量,比如template, user, repeat, request。下边是其他内建变量的完整列表和用途:

  • nothing -- 一个假值,类似于一个空字符串,你可以在tal:replace 或者 tal:content里使用来删掉一个标记符或它的内容。如果你把一个属性设置为nothing,这个属性就会从标记符中删除(或不插入),而不象空字符串。
  • default -- 当在tal:replace, tal:content, 或者 tal:attributes里使用时,是一个指定的值。它保持文本不变。
  • options -- 关键词参数,如果有的话,会传递给模板。注意::options只有当从python里边调用模板时才存在。当模板从web执行时,没有options。
  • attrs -- 模板里当前标记符的属性字典。键名为属性名称,键值为属性在模板里最初的值。这个变量很少用。
  • root -- Root对象。使用这个对象从某个固定的位置得到Zope对象,不管模板被放置在什么地方,或在什么地方调用。
  • here -- 模板被调用时的对象。这经常等同于container,但如果你使用获取,会不同。要在不同的地方找到你所要的Zope对象,这取决于模板是如何被调用的。Here变量类似于基于Python的脚本的context变量。
  • container -- 保存模板的容器(一般是一个文件夹)。使用这个对象可以从相对于模板位置得到Zope对象。当从普通位置调用模板时,Container和here变量指的是同一对象。然而,当对另外一个对象应用模板时(例如,一个ZSQL方法),这两个变量不再指同一对象。
  • modules -- 适合模板的Python模块集。参见编写Python表达式部分。

在本章,你会看到使用这些变量的例子。

+9.3.2 字符串表达式

字符串表达式允许你轻松的混合路径表达式和文本。所有在起始string:后边的文字是字符串表达式,并且搜索路径表达式。每个路径表达式必须用一个'$'保护起来。下边是几个例子:

          "string:Just text. There's no path here."
          "string:copyright $year, by me."

如果路径表达式有多个部分,或者需要和文本部分分开,它必须用大括号({})括起来。例如:

          "string:Three ${vegetable}s, please."
          "string:Your name is ${user/getUserName}!"

注意,上边的例子是如何表达的。你需要用大括号把vegetable路径括起来,这样Zope就不会弄错。

由于文本是位于属性值里边,通过使用实体句法",你才能在里边包括双引号。由于美圆符号已经用来 标志路径表达式,这样就需要再附加两个美圆符号($$)。例如:

          "string:Please pay $$$dollars_owed"
          "string:She said, &quot;Hello world.&quot;"

一些复杂的字符串格式操作(比如搜索和替换或更改大小写)不能轻松的由字符串表达市完成。对于这种情况,你应该使用Python 表达式或脚本。

+9.3.3 路径表达式(Path Expressions)

路径表达式通过URL路径指向对象。所有的路径用已知对象开始(比如内建变量,repeat变量,或者用户定义的变量)。以下是一些例子:

          template/title
          container/files/objectValues
          user/getUserName
          container/master.html/macros/header
          request/form/address
          root/standard_look_and_feel.html

通过使用路径表达式,你可以访问对象以及下级对象的属性和方法。你还可以在路径表达式里使用获取机制。您可以从“高级Zope脚本”里边的“从Web调用脚本”部分,查看更多的相关信息。

在路径表达式里,Zope采用通过URL访问对象一样的方式访问对象。你必须适当的访问对象的权限。参见第六章“用户和安全”相关部分。

+9.3.3.1替代路径

当每次使用模板时,路径表达式template/title可肯定存在,尽管它可能是一个空字符串。一些路径,比如request/form/x,在执行模板的过程中可能不存在。这样就会在Zope求路径表达式的值时引起错误。

当路径不存在,你可以使用一个替代路径或值。例如,如果request/form/x不存在,你可能想使用here/x。你可以实现这个功能,方式是按照路径引用的次序列出来,并用束线符号(|)分开:

            <h4 tal:content="request/form/x | here/x">Header</h4>

有两个变量作为替代变量时很有用,即nothing 和 default。例如,default告诉tal:content保持现有内容。不同的TAL语句对default和nothing有不同的解释。请参见附录C“Zope页面模板参考”部分。

在替代路径表达式里,你还可以使用非路径表达式作为最后一部分。例如:

            <p tal:content="request/form/age|python:18">age</p>

在这个例子里,如果request/form/age路径不存在,那么值就是18。这种形式允许你指定默认的值。注意,只能使用非路径表达式作为最后的替代表达式。

你还可以用存在表达式前缀直接检测路径的存在。参见下边的“存在表达式”部分。

+9.3.4 Not表达式(Not Expressions)

Not表达市让你对表达式求反,例如:

          <p tal:condition="not:here/objectIds">
            There are no contained objects.
          </p>

当表达式为假时,Not表达式返回真,否则相反。在Zope里,不存在的变量,0,空字符串,空序列,nothing和None被认为是假,其他的为真。

你还可以使用Python中的not关键字代替否表达式。

+9.3.5 Nocall表达式

通常,路径表达式会执行表达式里所包含的对象。这就意味着,如果对象是一个函数,脚本,方法,或一些其他可执行的对象,那么表达式会调用这个对象,求得结果。一般来说,需要这样,但并总需要这样。例如,如果你想把一个DTML文档放入到一个变量里边,从而为了引用它的属性,你不能使用通常的路径表达式,这是因为它会把文档执行成字符串。

如果你在路径前边加上前缀nocall:,就会阻止执行,只返回对象。例如:

          <span tal:define="doc nocall:here/aDoc"
                tal:content="string:${doc/getId}: ${doc/title}">
          Id: Title</span>

这种表达式类型另外一种用途是在你需要定义一个变量来处理函数或模块类时,用在Python表达式里边。 Nocall表达式除了对象还可以调用函数:

          <p tal:define="join nocall:modules/string/join">

这个表达式把变量join变量定义为函数('string.join'),而不是调用一个函数的结果。

+9.3.6 Exists表达式

如果表达式的路径存在,则exists表达式为真,否则为假。例如,以下是一种显示错误消息的方式:

          <h4 tal:define="err request/form/errmsg | nothing"
              tal:condition="err" 
              tal:content="err">Error!</h4>

你可以用exists表达式完成同样的功能:

          <h4 tal:condition="exists:request/form/errmsg"
              tal:content="request/form/errmsg">Error!</h4>

你可以结合exists表达式和not表达式,例如:

          <p tal:condition="not:exists:request/form/number">Please enter
          a number between 0 and 5</p>

注意,在这个例子里,你不能使用表达式::"not:request/form/number",这是由于如果变量number变量存在并且为0,那么表达式将为真。

+9.3.7 Python表达式

Python编程语言简单而富有表现力。如果你以前从没有用过,可以读一读Python 站点中的介绍或说明。

页面模板表达式可以包括任何Python语言认为是表达式的内容。你不能使用象if和while这样的语句。此外,Zope还对访问受保护的信息、更改安全数据和创建无限循环这样的错误进行一些安全限制。更多信息,请参见第八章“高级Zope脚本”里有关Python安全限制部分。

+9.3.7.1比较

Python表达式特别有用的一种场合是在tal:condition语句里。在你需要比较两个字符串或数字时,只能用Python表达式来完成。你可以使用比较操作符<(小于)、>(大于)、==(等于)和!=(不等于)。还可以使 用布尔操作符and,not和or。例如:

            <p tal:repeat="widget widgets">
              <span tal:condition="python:widget.type == 'gear'>
              Gear #<span tal:replace="repeat/widget/number>1</span>:
              <span tal:replace="widget/name">Name</span>
              </span>
            </p>

这个例子对一个对象集合进行循环,测试每个对象的type属性。

有些时候,你需要基于一个或多个条件在一条语句里选择不同的值。你可以通过test函数来完成这个功能,就象这样:

            You <span tal:define="name user/getUserName"
                 tal:replace="python:test(name=='Anonymous User',
                                         'need to log in', default)">
                  are logged in as
                  <span tal:replace="name">Name</span>
                </span>

Test函数就象if/then/else语句。关于test函数方面更多信息,请参见附录A“DTML参考”。这里是另外一个使用test函数的例子:

            <tr tal:define="oddrow repeat/item/odd"
                tal:attributes="class python:test(oddrow, 'oddclass',
                                                  'evenclass')">

没有test函数,你只能写两个适合不同条件的tr元素,一个用于偶数行,另外一个用于奇数行。

+9.3.7.2 使用其它的表达式类型

你可以使用Python表达式里边的其它表达式类型。每个表达式类型都有对应的同名函数,包括::path(), string(), exists()和 nocall()。这样就允许你编写下边的表达式:

            "python:path('here/%s/thing' % foldername)"
            "python:path(string('here/$foldername/thing'))"
            "python:path('request/form/x') or default"

比起path表达式"request/form/x | default",最后一个例子有一些略微不同的含义,这是由于如果"request/form/x"不存在或为假时,将使用默认的文字。

+9.4 使用Zope对象

Zope之所以强大,相当多的表现在可以结合多种特殊的对象。你的页面模板可以使用Scripts, SQL Methods, Catalogs,以及定制的内容对象。为了使用这些对象,你必须知道如何在页面模板里访问它们。

对象属性即通常的属性,因此你可以用表达式"template.title"得到模板的标题。大多数Zope对象支持获取机制,获取机制允许你从父对象得到属性。这就意味着Python表达式"here.Control_Panel"将从root文件夹获取Control_Panel对象。对象方法是属性,就像"here.objectIds" 和 "request.set"。文件夹里的对象能够以文件夹属性的方式访问,但经常会是它们的id并不是有效的Pytho标识,你不能使用通常的表示法。例如,你不能使用以下的表达式:

            "python:here.penguin.gif"'. 

你必须写为:

            "python:getattr(here, 'penguin.gif')"

这是由于Python不支持用点号隔开的属性名称。

一些对象,比如request, modules, 以及 Zope 文件夹支持Python条目访问。例如:

            request['URL']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27URL%27" title="create this page">?</a>
            modules['math']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27math%27" title="create this page">?</a>
            here['thing']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27thing%27" title="create this page">?</a>

当你使用条目访问文件夹,它并不试图获取名称,它只有在文件夹里确实存在具有这个Id的对象时才会成功。

如前几章所显示的,path表达式允许你忽略一些细节。Zope试着先访问属性,然后是访问条目。你可以写成:

            "here/images/penguin.gif"

来取代:

            "python:getattr(here.images, 'penguin.gif')"

又如:

            "request/form/x" 

来取代:

            "python:request.form['x']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27x%27" title="create this page">?</a>"

Path表达式不允许你指定这些细节。例如,如果你一个名为get的表单变量,你必须写成:

            "python:request.form['get']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27get%27" title="create this page">?</a>"

这是由于这个path表达式:

            "request/form/get" 

将对表单字典求get方法的值。

如果确实想这样的话,你可以在Python表达式里通过path()函数使用上边所述的path表达式。

+9.5 使用脚本

脚本对象经常用来处理事务逻辑和复杂的数据控制。当你发现编写TAL语句的时候采用了复杂的表达式时,就应该考虑是否用脚本来更好的完成工作。如果你觉得难以理解你的模板语句和表达式,最好就用脚本来简化页面脚本的复杂部分。

每个脚本都有一个参数列表,当调用脚本时应该提供这些参数。如果这个列表为空,那么你可以通过编写path表达式来使用这个脚本。否则,为了提供参数,就需要使用一个Python表达式,象这样:

            "python:here.myscript(1, 2)"
            "python:here.myscript('arg', foo=request.form['x']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27x%27" title="create this page">?</a>)"

如果你想从脚本给页面模板返回多个数据条目,一种好的方法是以字典的形式返回。这样时,你可以定义变量来存储所有的数据,用path表达式来引用每个条目。例如::假设getPerson脚本返回一个含有name 和 age键的字典:

            <span tal:define="person here/getPerson"
                  tal:replace="string:${person/name} is ${person/age}">
            Name is 30</span> years old.

当然,还可以返回Zope对象和Python列表。

+9.6 调用DTML

不象脚本,DTML方法和文档没有明显的参数列表声明。但是,它们希望传递的是client,映射,以及关键字参数。它们使用这些参数来构建名称空间。更多信息请参见第七章的显式调用DTML部分。

当Zope通过Web出版一个DTML对象时,它把对象相关参数作为client,REQUEST作为映射。当一个DTML对象调用另外一个,它把自己的名称空间作为映射传递,没有client。

如果你使用path表达式来调用一个DTML对象,它将传递一个带有request,here和模板变量的名称空间。这就意味着DTML对象如果发布在和模板一样的地方,则使用相同的各种名称,以及模板里定义的变量名称。

+9.8 Python模块

Python语言带有大量的模块,这些模块提供了很多功能。每个模块都是Python函数、数据和具有某一用途的类的集合,比如数学计算或规则表达式。

其中的一些模块,包括"math" 和 "string",在Python表达式里默认存在。例如,你可以从math模块里得到pi的值,写成"python:math.pi"。要从path表达式访问它,你就需要使用模块变量,写成"modules/math/pi"。

String模块在Python表达式里是隐藏的,因此你需要通过模块变量进行访问。你可以直接用在表达式里,或者定义一个全局变量,就像这样:

            tal:define="global mstring modules/string"
            tal:replace="python:mstring.join(slist, ':')"

实际上,你很少需要这样做,这是因为大部分时候都可以使用string模块,而不必依赖string模块里的函数。

模块可以组合成包,这是一种组织和命名相关模块的简单方式。例如,Zope里边基于Python的脚本是通过一组模块提供的,这组模块位于Products包里的PythonScripts子包。通常,这组模块里边的"standard"模块提供一些有用的格式函数,就像在DTML里的"var"标记符那样。这个模块的完整名称是"Products.PythonScripts?.standard",因此你可以使用以下任何一种语句访问它:

            tal:define="global pps modules/Products/PythonScripts<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=PythonScripts" title="create this page">?</a>/standard"
            tal:define="global pps python:modules['Products.PythonScripts.standard']<a class="new" href="http://members.czug.org/zope/zopebook/X_e9_ab_98_e7_ba_a7_e9_a1_b5_e9_9d_a2_e6_a8_a1_e6_9d_bf2/createform?page=%27Products.PythonScripts.standard%27" title="create this page">?</a>"

许多Python模块不能从页面模板,DTML或脚本进行访问,除非你给它们添加了Zope安全权限。这个过程超出了本书的范围,请参见《Zope开发指南》。

From xyb Thu Apr 8 18:12:06 +0800 2004 From: xyb Date: Thu, 08 Apr 2004 18:12:06 +0800 Subject: 乱码 Message-ID: <20040409101206+0800@www.czug.org>

"路径表达式"一节的第二段有乱码。


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: