现在的位置: 首页 > 综合 > 正文

plone ZPT深入介绍

2013年06月17日 ⁄ 综合 ⁄ 共 22827字 ⁄ 字号 评论关闭
 plone ZPT深入介绍

通常,tal:replace 和 tal:content语句会忽略HTML标记符,并把文本里的尖括号
  the story
当你要插入一段存储在一个属性里边或由其他Zope对象生成的HTML或XML时,这个特性是很有用的。例如,你可能有一些新闻条目,这些条目里包
含了简单的HTML标记,例如那些显示粗体和斜体的标记。当把它们插入到"Top News"页面里边时,你想保留这些,你就可以写成:
  A news item withHTML markup.
这样就会把带有HTML标记符的新闻条目插入到段落里边。
[url=http://315ok.org/boke/portal_factory#id34]哑元素(Dummy Elements)[/url]
通过使用内建的变量nothing,你可以包含模板里可见的页面元素,而在生成的文本里却不可见。比如:
  10213Example Item$15.34
这个功能用于填充最终要被动态内容替换掉的部分。例如,一个具有10行的表格在模板里通常只有1行。通过添加9行模拟行,模板的样子就更像最终的结果了。
并不总是需要在你的页面模板里使用tal:replace="nothing"机制来加入模拟内容。例如,你已经看到了一些tal:content
或 tal:replace元素内的内容往往在执行后被删掉。在这种情况下,你无须进行任何特定功能来确信模拟内容已经删除掉了。
[url=http://315ok.org/boke/portal_factory#id35]默认内容[/url]
通过在tal:content 或 tal:replace里使用default表达式,你可以保留标记符的内容。例如:
Spam
这也就意味着:
Spam
大多数的时候,你需要有选择性的包含默认的内容,而不总是包含它。例如:
Spam
注意::Python表达式在本章的后边阐述。如果getFood方法返回一个真值,那么就就把结果插入到段落里,否则使用默认的Spam。
[url=http://315ok.org/boke/portal_factory#id36]高级标记符重复[/url]
你已经在第五章看到了使用tal:repeat语句通常情况下可以完成什么任务。本节侧重于讲述一些这个语句的高级特性。
[url=http://315ok.org/boke/portal_factory#id37]重复变量[/url]
特别值得一提的是重复变量。重复变量提供了当前重复的相关信息。重复变量有以下属性:
[*]index - 重复的序号,从0开始 [*]number - 重复的序号,从1开始 [*]even - 对于偶数序号(0, 2, 4, ...)为真。 [*]odd - 对于奇数序号(1, 3, 5, ...)为真。 [*]start - 对于起始重复为真(index 0)。 [*]end - 对于结尾或最终的重复为真 [*]length - 序列长度,就是重复总次数 [*]letter - 用小写字母计次,"a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz"等等。 [*]Letter - 用大写字母计次。 [/list]
你可以使用路径表达式或Python表达式来访问重复变量的内容。在路径表达式里,由三部分组成,即repeat名称,语句变量名称和你要的信息名
称,例如repeat/item/start。在Python表达式里,使用通常的字典方式就可以得到重复变量,然后就可以访问信息属性,例如:
'python:repeat['item'].start'
[url=http://315ok.org/boke/portal_factory#id38]重复提示[/url]
这里是一些有用的提示。有些时候,你希望重复一个标记符,但不要合拢标记符。例如,你可能想重复几个段落标记符,但不需要在另外一个标记符里合拢他们。你可以通过使用tal:omit-tab语句实现这个功能:
  quotation
tal:omit-tag语句在本章后边进行描述。
尽管前边已经提到过,值得再提一次::你可以嵌套tal:repeat语句。每个tal:repeat语句必须有一个不同的重复变量名。以下是一个显示数学乘方表的例子:
  
   
      
        X x Y = Z
      
   
  
这个例子使用了Python表达式,其中的tal:omit-tag语句在本章后边进行进一步讲述。
如果你已经用过很多次DTML里边的dtml-in重复语句,你会已经遇到了批块化。批块化就是把一个大的列表分隔为多个小列表的过程。典型的是用
它来在一个web页面里显示一个大列表里的小列表项目。就比如搜索引擎如何批块化显示搜索结果。tal:repeat语句不支持批块化,但是Zope带有
一个批块化工具。见本章后边的“批块化”部分。
tal:repeat另外一个没有提供的有用的特性是排序。如果你想对一个列表排序,你或者编写自己的排序脚本(在Python里是相当容易的),或者你可以使用sequence.sort工具函数。以下是一个如何按照标题对一个列表排序,然后按照修改日期排序的例子:
  
    title
   
      modification date
  
这个例子试图通过在sort函数外边定义sort参数。在这个例子里,如何对序列排序的描述是在sort_on变量里定义的。关于sequence.sort函数的更多信息请参见附录B“API参考”。
[url=http://315ok.org/boke/portal_factory#id39]高级属性控制[/url]
你已经用到了tal:attributes语句。你可以用它来动态替换标记符属性,例如,对于a 元素的href属性。通过用分号分隔开属性,你可以对一个标记符替换多个属性:
link
你还可以用XML名称空间定义属性,例如:
  Description
简单的把XML名称空间前缀放在属性名称前面,你可以用XML名称空间创建属性。
[url=http://315ok.org/boke/portal_factory#id40]定义变量[/url]
通过使用tal:define属性,你可以定义你自己的变量。这样做有几个原因。一个原因是要避免在模板里重复编写长的表达式。另外一个原因就是要
避免重复的调用复杂的方法。一旦你定义了变量,你就可以在一个模板里多次使用。例如,下边是一个定义了变量的列表,后边测试它,并对它进行重复:
     
       id
     
   
tal:define语句创建了变量items,你就可以在任何地方的ul标记符里使用它。还要注意的是,在同一ul标记符里是如何使用两个TAL
语句的。有关如何对一个标记符使用多个语句方面的信息,请见本章后边的“TAL语句之间的交互”部分。在这个例子里,第一个语句分配变量items,然后
第二个语句在一个条件里使用它,并判断是否为真值。如果items为假值,那么ul标记符不显示。
现在,假设当没有条目时并不是简单的删去列表,而是显示一条消息。要实现这一点,在列表前加入以下代码:
There
Are No Items
当container/objectIds为假时,表达式not:container/objectIds为真,依次类推。参见本章后边的“Not 表达式”部分。
此时你还不能使用变量items,因为他还没有定义。如果你把items定义移到h4标记符前边,那么你不能在ul标记符里使用,这是因为它变成了
h4标记符的本地变量。你可以把定义放置在包括h4和ul标记符的其他标记符里,但是有一种简单的解决方法。通过在变量名称前放置关键词global,你
就可以在定义它的h4标记符到模板底部之间使用它:
There Are No Items
你可以通过用分号分隔开,使用tal:define定义多个变量。例如:
你可以定义任意多个变量。每个变量可以由它自己的全局或本地范围。你还可以在后边定义里引用前边的定义。例如:
通过使用tal:define,你可以增进模板的效率和可读性。
[url=http://315ok.org/boke/portal_factory#id41]忽略标记符[/url]
你可以删除带有tal:omit-tag语句的标记符。你会很少使用这个语句,但是有时候还是有用的。omit-tag属性删除一个标记符,但不影响标记符内容。例如:
this stays
执行后为:
this stays
这种用法,tal:omit-tag操作就像是tal:replace="default"。然而,当tal:omit-tag与其他TAL语句
(比如::tal:repeat)一起使用时,就显得更为有用。例如,这里是一种用tal:repeat创建10个段落标记符的用法:
  1
这样就会产生10个段落标记符,然而,span标记符并不会在输出里显示。
tal:omit-tag属性能够用表达式,尽管通常你只要用空表达式就行了。如果表达式为真,或没有表达式,那么语句标记符被删除。如果表达式为假,那么标记符不被忽略。这样就允许你根据动态情况有选择性的删除标记符。
[url=http://315ok.org/boke/portal_factory#id42]错误处理[/url]
如果在你的页面模板里发生了错误,你可以捕捉这个错误,并给用户显示一条有用的消息。例如,假设你的模板定义了一个使用表单数据的变量:
...
...
如果Zope遇到了一个错误,比如在表单数据里不能找到prefs变量,整个页面将终止;而你将得到一个错误页面。值得庆幸的是,通过使用tal:on-error语句以及错误处理机制,你就可以避免这种事情:
...
...
当执行模板时引发了一个错误,那么Zope就会查找tal:on-error语句来处理这个错误。它先在当前的标记符里查找,然后在合拢的标记符
里,就这样一直到顶级的标记符。当它找到一个错误处理器,它用错误处理表达式替换标记符内容。在这个例子里,span标记符将包含一个错误消息。
一般情况下,你将对一个标记符定义错误处理器,其中包含逻辑页面元素,例如表格。如果一个错误影响了绘制表格,那么错误处理器可以从页面里忽略表格,或者用某种错误消息替换它。
对于更为灵活的错误处理,你可以调用脚本。例如:
...
任何发生在div里的错误将调用handleError脚本。注意structure选项允许脚本返回HTML。你的错误处理脚本可以检测错误,并且根据错误的类型采取不同的处理方法。你的脚本访问错误是通过名称空间调用error变量。例如:
## Script (Python) "handleError"
##bind namespace=_
##
error=_['error']
if error.type==ZeroDivisionError:
    return "Can't divide by zero."
else
    return """An error occurred.
              Error type: %s
              Error value: %s""" % (error.type,
                                           error.value)
你的错误处理脚本可以采取各种处理方法,例如,它可以通过发送邮件记录错误。
tal:on-error语句并不意味着一般的例外处理。例如,你不能用来验证表单输入。你应该使用脚本,这是因为脚本允许你完成强大的例外处理。tal:on-error语句适合于处理执行模板时所发生的错误。
[url=http://315ok.org/boke/portal_factory#id43]在TAL语句之间交互[/url]
当每个元素中只有一个TAL语句时,执行的顺序是简单的。从root元素开始,执行每个的元素语句,然后访问每个下级元素,按照这个顺序,执行他们的语句,依次类推。
可是,存在相同的元素拥有多个TAL语句的情况。除了tal:content和tal:replace语句不能结合在一起外,任何语句的结合都可能出现在相同的元素里边。
当一个元素有多个语句时,他们的执行顺序如下:
[*]define [*]condition [*]repeat [*]content or replace [*]attributes [*]omit-tag
由于tal:on-error语句只有当发生错误时才出现,因此,它没有列出来。
采用这种顺序的原因是::因为一般先要设置其他语句里使用的变量,因此define放在第一位。接下来要做的事情是决定是否包含这个元素,因此
condition放在其次,并且还由于condition可能依赖于刚才设置的变量,因此,它放在define后边。能够用每次循环的值替换元素的各个
部分是很有价值的,因此repeat放在content replace 和 attributes前面。Content和replace
不能同时对同一元素应用,因此它们处于同一位置。Omit-tag位于最后,这是因为没有其他的语句依赖于它,并且它应该位于define和repeat
后边。
以下是一个包含多个TAL语句的例子:
Ex Text
注意tal:define语句是如何先被执行的,其他的语句依赖于它的结果。
当对元素结合TAL 语句时,你有三个应该知道的限制:
[*]对于单一的标记符,每一种语句当中只能应用一个。这是因为HTML不允许相同名称的属性出现多次出现。例如,你不能在同一标记符中出现两个tal:define。 [*]tal:content 和 tal:replace不能同时在同一标记符中出现,这是因为它们的功能是相反的。 [*]标记符中编写TAL属性的顺序不影响他们执行的顺序。不管你如何排列它们,TAL语句执行总是按照上边所描述的固定顺序执行。
如果你打破TAL语句的顺序,你必须在另外一个元素里合拢这个元素,可能是div或span,以及对这个新元素放入一些语句。例如,假设你想对一个项目序列进行循环,但要跳过一些。下边的例子试图编写一个模板,它从0循环到9,并跳过3:
  
    1
  
这个模板不会工作,这是因为在执行重复以前先检测条件。以下是解决这个问题的一种方式:
  
   
      1
   
  
这个模板通过在一个合拢的div标记符中定义n变量。注意,由于存在tal:omit-tag语句,div标记符不会在输出里显示。这种方式可能不好,但确实管用。也许将来版本里的页面模板会以一种更好的方式解决这个问题。
[b]*注意*[/b] 其实在Plone中,更加常用的是,采用tal:block来制作段落标记。
[url=http://315ok.org/boke/portal_factory#id44]表单处理[/url]
在DTML里,你可以使用一种“form/action对”的模式来处理表单。一个form/action对由两个方法或文档组成:
一个当中包含收集用户输入信息的表单,另外一个包含可以处理输入并返回结果的行为。表单调用行为。有关form/action模式方面更多信息请见第四章
“用DTML处理动态内容”。
Zope页面模板对于form/action模式不能很好的工作,这是由于它假设输入处理和回应是有同一对象来完成的。对于页面模板,不用
form/action模式,你应该使用form/action/response模式。Form和response应该为页面模板,action应该为
一个脚本。表单模板收集输入,然后调用回应脚本。回应脚本应该处理输入,然后返回一个回应模板。这种模式比form/action模式更为灵活,这是由于
它允许脚本返回任意数量不同类型的回应对象。
例如,以下是一个表单模板的一部分:
...
  
  
  
...
这个表单应该用以下脚本处理:
## 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()
这个脚本检验表单输入,并返回表单模板,如果存在问题就带有一个错误消息。你可以用关键字参数给页面模板传递额外的信息。关键字参数通过内建变量选项的形式存在。因此这个例子里的表单模板可能会包括这样一部分:
  Error message goes here.
这个例子显示了如何通过关键字参数给模板传递一个要显示的错误消息。
根据你的应用程序的不同,你可以选择让用户指向一个回应页面模板,而不是直接返回它。这样就形成了两次网络活动,但它的用途在于更改了显示在用户的浏览器中的URL,而不是回应脚本的URL。
如果你坚持要采用原来的方式,你可以用页面模板创建一个form-action对。但只有当你不关心错误处理时,你才能这样做,并且回应应该总是一
样,不管用户提交了什么。由于页面模板没有象dtml-call那样的等同语句,你可以使用任何一种方式来调用输入处理方法,而不用插入结果。例如:
这个例子调用了processInputs方法,并且把结果分配给unused变量.
[url=http://315ok.org/boke/portal_factory#id45]表达式[/url]
你已经用过了页面模板表达式。表达式给模板语句提供值。例如,路径表达式以赋予路径的方式描述了对象,比如request/form/age, 或者 user/getUserName这样的路径。在本节,你将学习各种类型的表达式,以及变量。
[url=http://315ok.org/boke/portal_factory#id46]内建变量[/url]
变量就是你在表达式里可以用的名称。你已经在一些例子里看到内建变量,比如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表达式部分。 [/list]
在本章,你会看到使用这些变量的例子。
[url=http://315ok.org/boke/portal_factory#id47]字符串表达式[/url]
字符串表达式允许你轻松的混合路径表达式和文本。所有在起始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, "Hello world.""
一些复杂的字符串格式操作(比如搜索和替换或更改大小写)不能轻松的由字符串表达市完成。对于这种情况,你应该使用Python 表达式或脚本。
[url=http://315ok.org/boke/portal_factory#id48]路径表达式(Path Expressions)[/url]
路径表达式通过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访问对象一样的方式访问对象。你必须适当的访问对象的权限。参见第六章“用户和安全”相关部分。
[url=http://315ok.org/boke/portal_factory#id49]替代路径[/url]
当每次使用模板时,路径表达式template/title可肯定存在,尽管它可能是一个空字符串。一些路径,比如request/form/x,在执行模板的过程中可能不存在。这样就会在Zope求路径表达式的值时引起错误。
当路径不存在,你可以使用一个替代路径或值。例如,如果request/form/x不存在,你可能想使用here/x。你可以实现这个功能,方式是按照路径引用的次序列出来,并用束线符号('|')分开:
Header
有两个变量作为替代变量时很有用,即nothing 和 default。例如,default告诉tal:content保持现有内容。不同的TAL语句对default和nothing有不同的解释。请参见附录C“Zope页面模板参考”部分。
在替代路径表达式里,你还可以使用非路径表达式作为最后一部分。例如:
age
在这个例子里,如果request/form/age路径不存在,那么值就是18。这种形式允许你指定默认的值。注意,只能使用非路径表达式作为最后的替代表达式。
你还可以用存在表达式前缀直接检测路径的存在。参见下边的“存在表达式”部分。
[url=http://315ok.org/boke/portal_factory#id50]Not表达式(Not Expressions)[/url]
Not表达市让你对表达式求反,例如:
  There are no contained objects.
当表达式为假时,Not表达式返回真,否则相反。在Zope里,不存在的变量,0,空字符串,空序列,nothing和None被认为是假,其他的为真。
你还可以使用Python中的not关键字代替否表达式。
[url=http://315ok.org/boke/portal_factory#id51]Nocall表达式[/url]
通常,路径表达式会执行表达式里所包含的对象。这就意味着,如果对象是一个函数,脚本,方法,或一些其他可执行的对象,那么表达式会调用这个对象,
求得结果。一般来说,需要这样,但并总需要这样。例如,如果你想把一个DTML文档放入到一个变量里边,从而为了引用它的属性,你不能使用通常的路径表达
式,这是因为它会把文档执行成字符串。
如果你在路径前边加上前缀nocall:,就会阻止执行,只返回对象。例如:
Id: Title
这种表达式类型另外一种用途是在你需要定义一个变量来处理函数或模块类时,用在Python表达式里边。
Nocall表达式除了对象还可以调用函数:
这个表达式把变量join变量定义为函数('string.join'),而不是调用一个函数的结果。
[url=http://315ok.org/boke/portal_factory#id52]Exists表达式[/url]
如果表达式的路径存在,则exists表达式为真,否则为假。例如,以下是一种显示错误消息的方式:
Error!
你可以用exists表达式完成同样的功能:
Error!
你可以结合exists表达式和not表达式,例如:
Please enter
a number between 0 and 5
注意,在这个例子里,你不能使用表达式::"not:request/form/number",这是由于如果变量number变量存在并且为0,那么表达式将为真。
[url=http://315ok.org/boke/portal_factory#id53]Python表达式[/url]
Python编程语言简单而富有表现力。如果你以前从没有用过,可以读一读Python 站点中的介绍或说明。
页面模板表达式可以包括任何Python语言认为是表达式的内容。你不能使用象if和while这样的语句。此外,Zope还对访问受保护的信息、
更改安全数据和创建无限循环这样的错误进行一些安全限制。更多信息,请参见第八章“高级Zope脚本”里有关Python安全限制部分。
[url=http://315ok.org/boke/portal_factory#id54]比较[/url]
Python表达式特别有用的一种场合是在tal:condition语句里。在你需要比较两个字符串或数字时,只能用Python表达式来完成。
你可以使用比较操作符(大于)、==(等于)和!=(不等于)。还可以使用布尔操作符and,not和or。例如:
  
  Gear #1:
  Name
  
这个例子对一个对象集合进行循环,测试每个对象的type属性。
有些时候,你需要基于一个或多个条件在一条语句里选择不同的值。你可以通过test函数来完成这个功能,就象这样:
You
      are logged in as
      Name
   
Test函数就象if/then/else语句。关于test函数方面更多信息,请参见附录A“DTML参考”。这里是另外一个使用test函数的例子:
没有test函数,你只能写两个适合不同条件的tr元素,一个用于偶数行,另外一个用于奇数行。
[url=http://315ok.org/boke/portal_factory#id55]使用其它的表达式类型[/url]
你可以使用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"不存在或为假时,将使用默认的文字。
[url=http://315ok.org/boke/portal_factory#id56]使用Zope对象[/url]
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']
modules['math']
here['thing']
当你使用条目访问文件夹,它并不试图获取名称,它只有在文件夹里确实存在具有这个Id的对象时才会成功。
如前几章所显示的,path表达式允许你忽略一些细节。Zope试着先访问属性,然后是访问条目。你可以写成:
"here/images/penguin.gif"
来取代:
"python:getattr(here.images, 'penguin.gif')"
又如:
"request/form/x"
来取代:
"python:request.form['x']"
Path表达式不允许你指定这些细节。例如,如果你一个名为get的表单变量,你必须写成:
"python:request.form['get']"
这是由于这个path表达式:
"request/form/get"
将对表单字典求get方法的值。
如果确实想这样的话,你可以在Python表达式里通过path()函数使用上边所述的path表达式。
[url=http://315ok.org/boke/portal_factory#id57]使用脚本[/url]
脚本对象经常用来处理事务逻辑和复杂的数据控制。当你发现编写TAL语句的时候采用了复杂的表达式时,就应该考虑是否用脚本来更好的完成工作。如果你觉得难以理解你的模板语句和表达式,最好就用脚本来简化页面脚本的复杂部分。
每个脚本都有一个参数列表,当调用脚本时应该提供这些参数。如果这个列表为空,那么你可以通过编写path表达式来使用这个脚本。否则,为了提供参数,就需要使用一个Python表达式,象这样:
"python:here.myscript(1, 2)"
"python:here.myscript('arg', foo=request.form['x'])"
如果你想从脚本给页面模板返回多个数据条目,一种好的方法是以字典的形式返回。这样时,你可以定义变量来存储所有的数据,用path表达式来引用每个条目。例如::假设getPerson脚本返回一个含有name 和 age键的字典:
Name is 30 years old.
当然,还可以返回Zope对象和Python列表。
[url=http://315ok.org/boke/portal_factory#id58]调用DTML[/url]
不象脚本,DTML方法和文档没有明显的参数列表声明。但是,它们希望传递的是client,映射,以及关键字参数。它们使用这些参数来构建名称空间。更多信息请参见第七章的显式调用DTML部分。
当Zope通过Web出版一个DTML对象时,它把对象相关参数作为client,REQUEST作为映射。当一个DTML对象调用另外一个,它把自己的名称空间作为映射传递,没有client。
如果你使用path表达式来调用一个DTML对象,它将传递一个带有request,here和模板变量的名称空间。这就意味着DTML对象如果发布在和模板一样的地方,则使用相同的各种名称,以及模板里定义的变量名称。
[url=http://315ok.org/boke/portal_factory#id59]Python模块[/url]
ython语言带有大量的模块,这些模块提供了很多功能。每个模块都是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/standard"
tal:define="global pps python:modules['Products.PythonScripts.standard']"
许多Python模块不能从页面模板,DTML或脚本进行访问,除非你给它们添加了Zope安全权限。这个过程超出了本书的范围,请参见《Zope开发指南》。
[url=http://315ok.org/boke/portal_factory#id60]Macros(宏)[/url]
到此为止,你已经看到了页面模板如何给独立的web页面加入动态的行为。页面模板的另外一个特性是许多页面可以重复使用外观和风格元素。
例如,使用页面模板,网站就可以有一致的外观和风格。不管页面的内容是什么,都将有一致的页眉,按钮条,页脚,以及其它的页面元素。对于web站点来说,这是一种非常普遍的要求。
你可以通过使用macros,你可以在多个页面里重复使用表现元素。Macros定义了多个页面之间共性的部分。一个macro可以为一个整个页
面,或者仅为页面的一部分,比如页眉或页脚。当你在一个页面模板里边定义一个或多个macro以后,就可以在其他页面模板里边使用它们。
[url=http://315ok.org/boke/portal_factory#id61]使用macro[/url]
你可以通过类似于TAL语句的标记符属性来定义macro。Macro标记符属性被称为macro扩展标记符属性语句(Macro Expansion Tag Attribute Language (METAL))。以下是一个定义macro的例子:
  Copyright 2001, Foo, Bar, and Associates Inc.
其中的metal:define-macro语句定义了一个名为"copyright"的macro。这个macro由p 和内容(包括所有被包括的标记符)组成。
在页面模板里定义的macro存储在模板的macro属性里边。你可以通过指向在其他模板里定义的macro属性来使用macro。例如,假设
copyright这个macro位于一个名为"master_page"的页面模板里边,以下显示了如何在另外一个页面模板里调用这个macro:
  Macro goes here
在这个页面模板里,b标记符在Zope执行这个页面时将完全用macro替换:
  Copyright 2001, Foo, Bar, and Associates Inc.
如果你更改了macro(例如,名称变了),那么使用了这个macro的页面模板都会自动反映出这种变化。需要注意的是macro是如何在path
表达式里通过使用metal:use-macro语句来识别的。metal:use-macro语句用macr替换语句的元素。o
[url=http://315ok.org/boke/portal_factory#id62]Macro细节[/url]
metal:define-macro 和 metal:use-macro语句还是相当易用的,但是有一些注意事项. Macro的名称在其被定义的页面模板里边必须是唯一的。你可以在一个模板里定义多个macro,但他们都需要是不同的名字。
一般你通过一个path表达式里用metal:use-macro语句来调用一个macro。然而,只要表达式返回一个macro, 就可以使用任何类型的表达式:
  Replaced with a dynamically determined macro,
  which is located by the getMacro script.
使用表达式来定位macro,可以让你动态的确定模板使用那一个macro。
你可以通过metal:use-macro 语句使用default变量:
  This content remains - no macro is used
这个结果与使用tal:content 和 tal:replace 语句是一样的,语句元素不变。
如果你试图通过metal:use-macro使用nothing变量,会得到一个错误,这是由于nothing不是一个macro。如果你想使用
nothing来有条件的包含一个macro,你应该用一个tal:condition语句合拢metal:use-macro语句。
Zope执行模板时会先处理macros。那么Zope对TAL表达式求值。例如,看以下的这个macro:
  template's title
当你使用这个macro,它将插入使用macro的那个模板的标题,而不是定义macro的模板的标题。换句话说,当你使用一个macro,就像是把macro的文字复制到模板里,然后执行你的模板。
如果你选中了页面模板在Edit视图里的Expand macros when
editing选项,那么你使用的任何macro都将在模板源文件里展开。这是Zope的默认行为,并且通常这是需要的,这是由于它允许你编辑完整而有效
的页面。但某些时候,特别是当你正在ZMI里编辑时,而不是使用WYSIWYG编辑工具,这时不展开则会更方便。此时,只要不选中这个选项就可以了。
[url=http://315ok.org/boke/portal_factory#id63]使用slots[/url]
当你使用macro时如果能够覆盖其中的某一部分,macro就更显得有用了。实现这个功能,可以通过在macro里定义slots的方式实现,这样当你使用模板时就可以填充它。例如,考虑一个栏目条macro:
  Links
  
    Home
    Products
    Support
    Contact Us
  
这个macro不错,但假设你希望在某些页面里的栏目条里加入一些附加信息。使用slots实现这个功能的一种方式是:
  Links
  
    Home
    Products
    Support
    Contact Us
  
  
当你使用这个macro,你可以这样来填充slot:
  
    Make sure to check out our specials.
  
当你执行这个模板,栏目条会包含你在slot里提供的额外信息:
  Links
  
    Home
    Products
    Support
    Contact Us
  
  
    Make sure to check out our specials.
  
注意定义slot的span元素是如何被slot填充b元素的。
[url=http://315ok.org/boke/portal_factory#id64]定制默认的外观[/url]
Slot的常见用途是来为可以定制的页面提供默认的外观。在上一部分里边的slot例子里,slot定义仅是一个空的span元素。然而,你可以在slot定义里提供默认的外观。例如,看以下这个修改过的栏目条macro:
  
  Links
  
    Home
    Products
    Support
    Contact Us
  
  
  
现在,这个栏目条可以充分定制。你可以填充links slot来重新定义工具条链接。然而,如果你不填充links slot,那么,你将得到默认的链接。
你甚至可以通过在slots里定义slots,进一步使用这种技巧。这样就可以让你覆盖默认的外观。以下是一个在slot内部定义slot的栏目条::
  
  Links
  
    Home
    Products
    Support
    Contact Us
   
  
  
  
如果你想定制栏目条链接,你可以填充links slot来完全覆盖现有的链接,还可以填充additional_links slot来在默认链接后边插入一些额外的链接。你可以任意嵌套slot。
[url=http://315ok.org/boke/portal_factory#id65]混合METAL和TAL[/url]
在相同的元素里可以同时使用METAL和TAL。例如:
  
    link name
  
由于METAL语句在TAL语句前求值,这里没有冲突。同时, 这个例子没有使用slot来定义macro。Macro调用getLinks脚本来决定链接。这样你就可以在站点里不同部分通过getLinks脚本来定制站点的链接。
通常, 在网站的不同部分都定制出最好的观感, 并不总是件容易的事情。一般来说,你应该使用slots来重载外观元素,并且使用脚本动态提供内容。在上边的例子里,需要确定链接是内容还是外观。通常脚本提供了一种更为灵活的方案,特别是如果你的站点包含链接内容对象。
[url=http://315ok.org/boke/portal_factory#id66]全页面Macros[/url]
使用macros不仅仅可以在不同页面之间共享外观元素,更可以使用macros来定义整个页面。Slots可以帮助实现这个功能。以下是一个定义整个页面的macro:
  
    The title
  
  
    title
   
      This is the body.
   
   
      Copyright 2001 Fluffy Enterprises
   
  
这个macro定义一个带有三个slots, 即headline, body, 和 footer。注意headline slot是如何通过一个TAL语句来动态确定headline内容。
你就可以在页面里使用这个macro来表现不同类型的内容,或者站点不同的部分。例如,以下是一个模板如何使用这种macro来表现新闻条目的:
  
    Press Release:
    Headline
  
  
    News item body goes here
  
这个模板重新定义了headline slot,从而包含了单词"Press Release",并且对当前对象调用getHeadline 方法。他还重新定义了body slot ,从而对当前对象调用getBody 方法。
这种方法强大的一方面在于你可以更改页面macro,这样press release模板就会自动更新。例如,你应该表页面正文放入表格里,并在左边加入一个栏目条,press release模板就会自动使用这些新的外观元素。
比起DTML里边的standard_html_header 和
standard_html_footer方法,这是一种更为灵活的解决方式。事实上,Zope在root文件夹里带有一个名为
standard_template.pt 的stock页面模板,它包含一个带有head和body
slot的页面macro。以下显示了如何在模板里使用这个macro:
  
    Title
    Body text goes here
  
使用standard_template.pt
macro非常类似于使用其他的全页面macros。唯一需要说明的是用来定位macro的路径。在这个例子里,路径用here开始。这样,Zope就会
使用获取机制来搜索standard_template.pt对象,从应用模板的那个对象所处位置开始。这样允许你通过在各个位置创建特定的
standard_template.pt对象来定制外观和感觉。这种方法就像覆盖站点不同位置的standard_html_header 和
standard_html_footer来定制外观和感觉。然而,使用standard_template.pt,你可以有更多的选择。你可以像采用
here那样,对root或container给macro起用path。如果path由root开始,那么你将总是得到位于root文件夹里边的标准模
板。如果path由container开始,那么Zope将通过使用获取机制搜索标准模板,开始的文件夹是定义模板的文件夹。这样允许你定制模板的外观和
感觉,但不允许你定制不同位置的对象的外观和感觉。
[url=http://315ok.org/boke/portal_factory#id67]缓存模板[/url]
通常执行页面模板是相当快的,有时不是足够快。对于经常访问的页面或需要长时间执行的页面,你需要适应速度的动态行为。缓存可以帮助你实现这些。关于缓存,可以查看第三章“基本对象”里边的“ 缓存管理器”部分。
你可以像缓存其他对象一样使用缓存管理器来缓存页面模板。要缓存页面模板,你必须用一个缓存管理器关联它。实现这点,你可以进入模板的Cache视图,并选择缓存管理器,还可以进入缓存管理器的Associate视图,然后选择你的模板。
以下是一个如何缓存页面模板的例子。首先,创建一个基于Python 的脚本long.py, 内容如下:
## Script (Python) "long.py"
##
for i in range(500):
  for j in range(500):
    for k in range(5):
      pass
return 'Done'
这个脚本的目的是要限制执行时间。现在,创建一个使用这个脚本的页面模板,例如:
  
    results
  
现在观看这个页面,注意它花费了一些执行时间。现在,让我们用缓存来提高执行速度。先创建一个Ram Cache
Manager。并确定它创建在与页面模板相同的文件夹里,或者在更高一级的目录里。现在观看Cache视图。选择刚才创建的Ram Cache
Manager,然后点击Save Changes。单击Cache
Settings可查看配置情况。默认的情况下,缓存内的对象存储时间为一个小时(3600秒)。根据你的应用程序的需要,你可以调整这个数字。现在返回
你的页面模板,再次观看它。这个过程会花费点时间来处理。现在重新调用这个页面,就会发现立刻就出来了。你可以一次又一次的调用这个页面,它总是迅速的出
来,这就是缓存的作用。
如果你更改页面模板,它就会从缓存里删除。因此,下一次观看它时,就会花费点时间来处理。当它再次被存入缓存后,就会快了。
缓存是一种简单而非常强大的增进性能的技术。使用缓存很容易,并且可以明显的提高速度。那些对性能要求高的应用程序,使用缓存是非常值得的。
[url=http://315ok.org/boke/portal_factory#id68]页面模板工具[/url]
Zope页面模板强大而简单。它不象DTML,页面模板不提供一些便利的特性,比如批块处理,绘制树结构,排序等等。页面模板的创建者想让它简单。这样的话,就可能失去一些DTML提供的内建特性。为了满足这些需要,Zope提供了一些用于加强页面模板的工具。
[url=http://315ok.org/boke/portal_factory#id69]批块化处理巨大的信息集合[/url]
当一个用户查询数据库,得到上百个结果,比起在一个页面里显示这些结果,有一种通常更好的显示方式,那就是采用多个每页只显示20个结果的页面。把巨大的列表分割为多个小的列表就被称为批块化。
页面模板不象DTML那样把批块化功能内建到语句里边,页面模板支持批块化是通过使用一种特殊的批块对象,这种对象由ZTUtils 工具模块提供。有关这个模块的更多信息请参见附录B“API参考”。
以下是一个简单的例子,显示了如何创建一个批块对象(Batch object):
  0
  
这个例子按照每次10个条目来处理列表(数字从0到9)。批块对象把一个长的列表转化为群组或批块。在这个例子里,是把含有一百个条目的列表分成多个包含10个条目的批块。
你可以通过传递一个不同的其始数字来显示不同的批块:
这个批块从第14个条目开始,并以第23个条目结束。换句话说,它显示的数字是从13到22。需要注意的是批块的start参数是第一个条目的索引
(index)。索引从0开始计算,而不是从1。所以,索引13代表的是序列里边第14个条目。Python使用索引来指向列表条目。
通常,当你使用批块时,你需要使用导航元素来让用户在批块之间进行跳转。以下是一个说明如何在多个批块之间进行导航的例子:
  
    The title
  
  
  
    previous
    next
  
  
   
      Bob Jones
      makes $100,000
      a year.
   
  
  
这个例子采用一个名为getEmployees 的ZSQL方法来处理批块数据。它根据需要来显示previous 和next链接,这样就可以通过每次浏览一个批块的方式来查看所有的结果。
让我们看看body元素里边的tal:define语句。它定义了一组批块变量。变量employees
是一个大的雇员对象的列表,它由名为getEmployees 的ZSQL方法返回的。第二个变量start被设为request/start
的值,或当request里边没有start变量时值为0。变量start跟踪你正在观看的雇员列表的位置。变量batch是一个含有10个条目的批块。
这个批块从变量start指定的位置开始。变量previous和
next指向前一个和后一个批块(如果有的话)。由于所有这些变量是在body元素里边定义的,因此它适用于body内部所有的元素。
接下来,让我们看看导航链接。它们创建可以浏览前一个和后一个批块的链接。语句tal:condition首先来判断是否存在前一个和后一个批块。
如果有前一个或后一个批块,那么就显示链接,否则为空。语句tal:attributes创建前一个和后一个链接。链接根据含有批块起始索引的查询字符
串,来显示为简单的URL或者当前的页面('request/URL0')。例如,如果当前的批块由索引10开始,那么前一个批块将从索引0开始。批块的
first变量提供开始的索引,这样在这个例子里,前一个批块将从0开始。
全部理解这个例子的工作原理并不重要。先复制它,或者使用一个由Z Search Interface
创建的批块例子。然后,当你需要更为复杂的批块处理时就可以通过更改这个例子来实验。别忘了参考附录B“API参考”,其中可以查看ZTUtils模块和
Batch对象。
[url=http://315ok.org/boke/portal_factory#id70]其它的工具[/url]
Zope提供了一些Python模块,这些模块在使用页面模板时会很方便。string, math, 和
random模块可以在Python表达式里分别用于字符串处理,数学函数和随机数字的生成。这些模块同样存在于DTML和基于Python的脚本里边。
有关这些模块的更多信息请参见附录B“API参考”。
Products.PythonScripts.standard模块用于提供基于Python的脚本工具,同样适用于页面模板。它包含了各种字符串和数字处理函数。相关信息请参见附录B“API参考”
就像本章前面提到的那样,序列模块提供了一种方便的排序功能。详细请见附录B“API参考”。
AccessControl模块包含了一个函数和类,它们可以用于测试权限,并得到授权的用户。更多信息,请参见附录B“API参考”
[url=http://315ok.org/boke/portal_factory#id71]结论[/url]
这一章讲到了页面模板的方方面面,读后,你可能感觉有一些多。不用担心,要想有效的使用页面模板,你不必掌握本章所讲述的全部内容。你应该理解
path类型和macros的不同,剩下的内容可以在需要的时候再回来查看。本章所学习的内容在需要的时候再查看是可以的,这些内容为你提供了需要知道
            
   
            
               
               
            
            
            
            
        
        
        
           类别(s)
                  
                  
                  Python/Zope/Plone
                  
               
        
        
            
               [*]
                       
[url=http://315ok.org/boke/plone-zptshenrujieshao]博客主体[/url]
                   [*]
                       ¦
                       [*]
                           
[url=http://315ok.org/boke/plone-zptshenrujieshao#comments]评注 (0)[/url]
                       [*]
                       ¦
                       [*]
                           
[url=http://315ok.org/boke/plone-zptshenrujieshao#trackbacks]反馈 (0)[/url]
                        [/list]

抱歉!评论已关闭.