译者 sunbaby,jzx++ 
如要转载请注明作者

不好意思,我们第一次翻译,如有翻译的不正确的地方,欢迎指正。来信请到 [MAILTO] [email protected] 谢谢

::-- ZoomQuiet [2005-08-22 07:12:30]

3. Zope 产品

3.1 概论

Zope产品具有新的功能,扩展了Zope。它们通常提供新可增加对象,但也通过新DTML标签,基于类的新ZClass,以及其他服务扩展Zope。

在Zope里有两种方式创建产品:一是通过WEB,二是文件系统中的文件。本章将讨论如何在文件系统上创建产品。至于通过WEB创建产品和ZCLASS的有关信息,请参见Zope Book,第12章。

相对于WEB产品,文件系统产品开发费用更高,但功能及弹性更强,而且他们可以通过比较熟悉的工具,如Emacs和CVS开发。

本章所涉及的产品例子,很快我们将提供网上下载,到那时,目前还不能看的本章中的一些文件参考将可用。 3.2 开发过程

本章首先讨论如何开发产品,着重于在开发产品过程中所遇到的普通工程任务。

3.2.1 考虑其它方法

在开发产品前,你首先应该考虑一下你的问题是否可以用ZCLASS、外部方法或Python脚本来解决更好。产品在扩展Zope用对象的可增加新类具有优越性,如果这点恰与你的解决方案不匹配,你应当寻找别的方案。产品像外部方法那样,允许在文件系统中无约束的写Python代码。

3.2.2 从接口开始

创建PRODUCT的第一步是创建PRODUCT中所描述的一或多个接口,如何创建接口及相关详细信息请参见第一章。

应当在开始执行前创建接口,因为这有利于你的设计和更好的评估它满足你的需求的情况。

可以随意命名接口,但是不要用如"I"及其它特殊的标识符。

3.2.3 实现接口

为你的PRODUCT定义了一个接口后,下一步是在Python中创建一个原型来实现它

可以交互使用并测试此类。下面是一个交互测试的例子。

"Green", "Blue", "I forget"])

交互测试提供了一种简单但强有力的测试代码的途径,是Python的一大优越性,通过不断的测试和提炼接口及执行它们的类。对于测试的有关详情,请参见第七章。

目前为止,我们已经知道如何创建Python类,并用接口及测试证实。下一步将检验Zope product构架,然后你将学会如何用构架来把你的Python类组成一个product框架。

3.3 构建Product类

把一个组件转换成产品需要满足很多规范,这些规范大部分在接口中定义,从基类子类化出符合规范的产品,这复杂化了产品的建立,这一点我们正努力完善和提高。

3.3.1 基类

基类的顺序取决于你想要的优先级,大多数Zope类不会定义相似的名字,因此通常不用担心product中这些类的顺序。让我们逐一看一下这些基类。

3.3.1.1 Acquisition.Implicit

Reference,ZOPE的许多服务,如对象Publishing、安全对象。

因此,Acquisition.Implicit类是products所需要的。事实上,你可以选择从Acquisition.Explicit继承,但它会组织从类的实例中动态绑定的Python Scripts 和 DTML Methods,通常你需要从Acquisition.Implicit中继承。

3.3.1.2 Globals.Persistent

instances)。关于"持久化"及此类的信息,参见第4章。

为了使你的Poll类持久化,你需要做一点变化。既然_votes是变化不定的非持久化子对象字典,你改变它时,需要让永久性对象知道。

此方法的最后一行把_p_changed的属性置1,通知持久对象已经改变并标记为脏,这意味着当前事务需要把新状态写进数据库。更详细的解释见Persistence 章节。

3.3.1.3 OFS.SimpleItem.Item

这个基类提供了使你的产品对象可以工作在ZMI中,通过从Item继承,你的产品增加了很多功能(剪切/粘贴/查看、WebDAV/FTP支持、undo支持、ownership支持、Traversal、各种标准ZMI视图、错误信息显示),具备getId()/title_or_id()/title_and_id()/this()等DTML方法,支持dtml-tree标签。 注意: Item需要你的产品类设置以下属性:meta_type、id or name、title

string,也是产品出现在产品添加列表中的名字。例如,poll product类的meta_type是Poll

用来唯一的标识容器中的实例。你也可以用name来代替id属性

所有的Item实例都必须有一个string类型的title属性. 如果你的实例没有title可以保持title为空字符串

class就像一个Item一样正常工作,需要做些改动。必须增加meta_type

最后,你应该把Item放在基类列表最后,因为Item提供如ObjectManagerPropertyManager类的默认override功能。你可以在Item中override 排在前面的类的方法

3.3.1.4 AccessControl.Role.RoleManager

这个类提供了是你的产品能够通过ZMI定义安全策略。关于安全策略的更多信息,参见第6章。

3.3.1.5 OFS.ObjectManager

这个基类提供了似你的产品可以包含其它的Item实例,换句话说,可以让你的产品就像Zope文件夹一样,这个基类是可选的,参考API参考可以获取更多信息。

这个基类提供了添加Zope对象,导入和导出Zope对象,WebDAV和FTP,它也提供了 objectids,objectValues,objectItems方法。

ObjectManager对于子类化它几乎没有什么要求,一般而言你不需要override它的方法

如果希望控制product的实例所包含对象的类型,可通过设置meta_types类属性实现,,meta_type属性一般用来创建专门的容器产品

3.3.1.6 OFS.PropertyManager

这个基类提供了使实例具有可以被用户管理的属性,查看API手册可以获得更多的信息,该基类是可选的。

你的类可以指定一个或多个预先定义的属性,通过设置_properties属性,例如

_properties结构是一个Sequence字典,其中每个字典代表一预定义的属性。需注意的是如果在_properties structure中定义一个预定义的property ,你必须在类或者实例中提供一个相同名字的属性(可以包含默认值或者是预定义的)

_properties结构的每个实体至少需要一个id和一个type键。其中id是property的名字,type是对象的类型字符串,而且类型必须是以下内容之一:float, int, long, string, lines, text, date, tokens, selection, or multiple section.想了解更多的关于Zope properties的信息,参见Zope Book.

properties,需要在属性字典中包括一addition item。select_variable 提供属性或方法的名字,返回被选中的字符串列表,如:

structure的每个entry中可能存在一可选项mode key,此键标识多种多样的属性。如果mode string需要表示,必须是w,d,或wd。

表示用户可以删除属性。一个空的empty mode表示此属性,并且此属性的值可以在属性列表中显示,但是其值为只读属性,不能被删除。

项目,默认为有一mode wd (可更改和删除)。

3.3.2 安全声明

把component转换成product,除了继承诸多标准基类外,还必须declare security information(声明有关安全信息)。关于安全信息及应用指导,详情见第6章。

为了声明安全信息,需要到Zope中设置初始化一下产品类,下面是一如何初始化poll class的例子:

3.3.3 总结

class了,测试前须在Zope中注册product class。

3.4 注册Products

包(packages),在Zope启动时被载入,此过程称产品初始化。通过产品初始化,每个产品都会register它的功能。 3.4.1 Product初始化

函数,并且传给它一个registrar object。此initialize 函数通过registrar告诉Zope它的功能。下面是一init.py file的例子:

object把类作为一个可增加对象来注册。registrar通过类的meta_type找出位于在product add list中的名字。Zope会根据类的meta-type自动找出一个权限名字,在这里例子中叫做 Add Polls(Zope会自动以产品的类名后加"s"),构造的参数是由两个函数组成的对象,一个是add form,另一个是add method。

注意你无法限制containers包含类的实例的类型。换句话说,如果类已经注册的话,假如用户拥有constructor允许权限,此类将显示在product add list中。

Reference。

3.4.2 工厂和构造

Factories允许创建Zope对象,对象可加入到folders,也允许创建其他对象管理器。(关于Factories,参见Zope Book的第12章)。一个Factory的基本功能是把类名放到product add list中,并为此名字联一个permission和action。如果你有允许权限,将在product add list中看到此类名,当选中此类名时,action method被调用。

list中创建Product类的实例。在上面的product初始化例子中,我们知道了product registrar如何创建一个factory,下一步我们将看一下如何创建add form和add list。

class创建instance的函数,返回值为HTML form。通常此HTML form收集instance的id,title及其他相关数据。下面是poll class的add form函数的简单例子:

的lines被排成一sequence。关于argument marshalling和object publishing的更多信息,参见第2章。

tag是非常重要的,因为这样Zope可以设置一个基本的URL以确保与addFunction 相关连接正常工作。

function,第一个参数是产品添加的位置(通常是Folder)。Add function 也可以传入任何根据一般对象发布规则发布的form变量

Destination:product被加进的对象管理器(ObjectManager )的位置

类的_setObject() 方法的的。关于ObjectManager 接口的更多信息,参见API Reference

function应当检查其输入的有效性。如果有问题问题或参数不是正确类型,add function应当提示。

class的方法,实际上,它们(constructor函数)在product class的任何instance被调用前就被调用;构造器功能需要有doc strings才能发布在web上,并在产品初始化是被权限设置所保护。

3.4.3 测试

form和add method加入到poll模块中,然后在lib/python/Products 目录下创建Poll 目录,并把Poll.py, PollProduct.py, 和 init.py 文件加入到该目录下,最后重启Zope。

以manager身份登录ZMI。在控制面板的Products目录下,你将看到一Poll product列表;如果Zope初始化product出错,这儿将显示traceback,如果product有错误,改正后重起Zope。如果重起Zope你嫌太麻烦,可以参考第7章的Refresh facility。

现在转到根目录下,从产品添加列表中选择Poll。注意添加到add form需要:提供一id, 一个question,一个responses列表,单击Add即可。出现了黑屏,是因为你的add method没有任何返回值。而且你发现,poll有一个broken icon(图标),且仅有management views,先不要管它,下一部分我们将讨论如何解决这些问题。

Scripts来测试你的poll instance。下面是计算投票百分比的Script:

Note,

Method:

value="&dtml-sequence-index;">

实例里调用它即可。注意DTML是如何调用poll实例和getPercentFor Python script。

在这一点,需要大量的测试的提炼工作。每改动一点product class,都必须重起Zope,这点非常讨厌。可参考第7章有关如何避免重起Zope的信息。如果你大量的改动你的class,可能破坏现存的poll instances,这样你需要删除这些instances,并创建新的instances。参见第7章有关的调试技巧信息。

3.5 创建管理界面

既然现在有了可以工作的product,让我们看一下如何如何创建用户界面和在线管理界面。

3.5.1 定义管理Views

products可通过web管理。Products具有管理的tabs或views,允许管理者来配置product。

attribute(类属性)中定义,下面是一个例子:

structure是一个含有字典的tuple,每个字典定义一个management view,view字典含有数个items。

:是被选view被调用时的URL,通常是显示management view的一个方法的名字。

frame。一般很少会用到。

:可选项。有关view的帮助信息。以后的章节可以学到有关help的更多内容。

views按定义的顺序显示,但是只有当前用户有允许权限的这些Management views才能显示出来。这就意味着不同的用户在管理product时,看到的management views不同。

views和重用一些已经存在的基类中已被定义的views。下面是一例子:

view,包含被Item 定义的Security,Undo和Ownership,一般情况下你应该包含着这些标准管理view。如果你的类具有一个默认index_html,那么你应该包含一个action为空的View View,关于index_html 更多信息,参见第2章。

view作为类的第一个view,因为当单击Zope management interface的一个对象时,将显示第一个management view。如果View view被第一个显示,view tabs将不可见,这样用户就不能浏览其他的management views。

3.5.2 创建管理 Views

类从文件中创建DTML 方法,例如:

Method,此方法在dtml/edit.dtml 文件中定义。注意你不需要包含.dtml 扩展文件,而且也不用担心作为路径分隔符会出问题,一般这样的转换在Windows上都可以运行。通过转换,DTML伟建就会放置到产品的dtml子目录里。

参数作用是允许其定位product 目录。如果你在调试模式下运 行Zope,DTML 文件的变化立刻被反映出来,也就是说,你无须重起Zope,就可以看到这些改变。

DTML 类的方法和其他方法一样,可以通过web直接调用。因此用户可以通过调用poll 类的实例的editForm 方法来显示编辑表单。通常DTML方法是用来在实例中收集显示信息的。你可以用一般的方法包装你的DTML方法,这样你可以在调用它之前计算DTML所需要的信息,也保证用户总是通过你的包装对象来访问DTML,参见下面例子:

在底部。Product需要这些变量构建一个标准的管理view header, tabs widgets, 和 footer.其中,管理 view header包括CSS信息,这样如果需要你可以方便的向management views中加入CSS类型信息。管理 CSS信息在lib/python/App/dtml/manage_page_style.css.dtml文件中定义,下面是在此文件中定义的CSS类和在使用时的所作的转换的例子:

:与forms相关的解释文本。以后,用户可能可以隐藏此文本。

std-text:也forms无关的所声称的文本。可能很少用到此项。

bug,此类在textarea 元素中不可用。

问题和答案(见editPollForm.dtml):

class="form-element"></td>

form允许改变问题及答案,注意poll属性是个HTML引用,它的值为在dtml-var中使用的html_quoted标记或者是dtml-var实体类型

假定这个DTML保存在product的dtml目录下的editPollForm.dtml 文件中,下面是在你的类中如何定义此方法:

'editPollForm')

允许权限保护,这确保了只有管理者才能调用此方法。

注意这个form的action也是editPoll.既然poll不包括任何编辑方法,需要定义一个来接受改变,下面是一个editPoll 方法。

方法如何通过新的editPoll方法被反射,另外,注意editPoll方法改变Poll时是如何被一个新的权限保护的。

方法仍然有一个问题:当从WEB调用editPollForm时并没有返回任何东西,这样的管理界面比较糟糕。

响应,但从init调用时,不希望返回HTML响应。下面是解决方法:

changed.')

参数,关于object publishing更多信息,参见第2章。这样通过REQUEST ,你可以判断此方法是否从WEB调用,如果从WEB调用,就再返回edit表单

界面的约定,应当用manage_tab_message DTML变量,如果在调用管理view时设置此变量,它将在页面顶部显示一条状态信息,利用此状态信息提供给用户反馈信息,告诉用户他们的actions已经生效(这些actions改变不容易看出)。例如,如果不为editPoll方法返回状态信息,用户可能意识不到所做的改动。

有时在显示管理views时会把不该高亮度显示的tab页高亮度显示了,这是因为从URL中manage_tabs 不能判断哪个view应当被高亮度显示。解决此问题只须设定要被高亮度的view的 management_view 变量给label,下面是一个用editPoll 方法的实现例子:

changed.')

3.5.3 图标

interface用Icon定义。Icon是16*16像素的GIF图片,其背景为透明。通常,icons文件存在product package的www 子目录下,如何把icon和product class联系起来?

参数。例如:

子目录中已经存在了的

方法的更多信息,见API Reference。

3.5.4 在线帮助

Zope提供在线帮助系统,主要是上下文相关的帮助和API帮助,你也可以为你的product提供这两大部分帮助。

3.5.4.1 上下文相关的帮助

目录下,为你的每个management view创建一个帮助文件,此文件的格式有以下几种选择:HTML, DTML, structured text, GIF, JPG, 和 PNG.

方法来注册帮助文件。如下所示:

此方法负责找到帮助文件,并为每个帮助文件创建帮助主题。可识别的帮助文件扩展名有:.html, .htm, .dtml, .txt, .stx, .gif, .jpg, .png.

如果你想更多的控制创建帮助主题,用registerHelpTopic() 方法,它有一个id 和 a 帮助 主题对象。例如:

interface。更多信息见API Reference。

把帮助主题和管理界面绑定,最主要的方法是在class 的manage_options 结构中包括关于帮助主题信息。例如:

package名字、帮助主题的文件名字(或其他的id )的tuple。提供此help 值,Zope将在管理界面上自动的为帮助主题生成一个Help按钮并链接到你的帮助主题

在管理界面上生成一个help按钮而不是一个view(像add form那样)的方法时使用HelpSys 对象的HelpButton。方法如下:

button。如果你想生成你自己的help button,可用helpURL方法,如下:

这样就给帮助主题了一个URL。可以选择生成任何类型的按钮和连接。

3.5.5 其它用户界面

管理界面,也可能完全的通过其它的网络协议控制。除了通过WEB提供管理界面之外,products也支持很多其它的用户界面。Zope提供了支持FTP, WebDAV 和 XML-RPC的 接口,如果这还不够,还可以增加其它的协议。

3.5.5.1 FTP 和 WebDAV 接口

WebDAV对待Zope对象像文件和目录,更多信息见第2章。

继承的子类,无需做任何工作,就可以得到基本的FTP和WebDAV支持。你的对象将出现在FTP目录列表中,而且,如果你的类是ObjectManager ,可以通过FTP 和 WebDAV访问它的内容。更多有关FTP 和 WebDAV支持的信息,见第2章。

3.5.5.2 XML-RPC和网络服务

XML-RPC在第2章中介绍。所有product的方法,均可通过XML-RPC访问,然而,如果你需要实现网络服务功能,就要使用XML-RPC应当设计一个或多个方法。

既然XML-RPC允许简单字符串、列表和字典的数据编组(marshalling),它也只能接受和返回这些类型的数据,不能接受和返回Zope对象。XML-RPC也不支持None ,因此需要用零或其它方式代替None.

使用XML-RPC需要考虑的另一个方面是安全。许多XML-RPC客户端都不支持基本的HTTP授权。根据不同的XML-RPC客户,需要编写公共的XML-RPC方法并通过参数接收授权证书。

3.5.5.3 内容管理框架接口(CMF)

是Zope的一绩效内容管理扩展,它为内容对象提供数个接品和转换,如果你想支持CMF,应当查阅CMF用户接口guidelines和界面文档。

interfaces就变得很容易了。如果你的product 类处理可管理的内容,如文档、图片、商业表格,你需要考虑支持CMF。

3.6 Products打包

products被打包为tar压缩包,在Products目录下创建压缩包时应当允许解包。例如,cd 到Products目录下,执行 tar 命令如下:

这将创建一个含有你的product的tar压缩包,product档案的文件名里应当包括product名字和版本号。

[WWW] http://www.zope.org/Documentation/Books/ZDG/current/examples/Poll-1.0.tgz 文件

3.6.1 Product信息文件

文件,还应当包括Product的一些信息。

README.txt:提供产品的基本信息。Zope解析此文件为文本,在product控制面板里,可以用README view阅读。

VERSION.txt:在一行里显示product名字和版本号,如Mutiple Choice Poll 1.1.0. Zope将把此信息作为version 属性显示在你的product的控制面板里。

LICENSE.txt:包含product许可证,或是它的一个连接。

也许你还想提供一些附加信息。下面是你的产品包含的一些可选的文件:

INSTALL.txt:提供特殊product安装说明及它所需元件的说明。此文件可选仅当product在Zope安装时只有一个ungzip/untar。

TODO.txt:此文件阐明何处这个product发布需要的工作以及作者的意图。

版本的变化信息和最近的变化信息;HISTORY.txt 是旧的变化信息。

required Zope version, required Python packages, and required Zope products的列表。

3.6.2 产品目录规划

如果在这些目录里,你没有任何东西要放,就没有必要创建它们。

3.7 Product Frameworks

products是一件复杂的事。有很多frameworks可帮助你减轻复杂程度,不同的frameworks注重product构建的不同方面。

3.7.1 ZClass Base Classes

blown products,Python base classes可被ZClasses使用,这就允许你只注重逻辑应用,而由ZClasses实现管理界面

此方法的最大障碍是关于ZClass和Python基类的代码将分开,这样,更难于编辑和可视化。

3.7.2 TransWarp and ZPatterns

Sarna开发的两个相关的Products架构

Page([WWW] http://www.zope.org/Members/pje/Wikis/ZPatterns/HomePage)

Page([WWW] http://www.zope.org/Members/pje/Wikis/ZPatterns/HomePage)

3.8 进化中的Products

类时,通常需要发布一系列的product,当你事先不知道product将会如何改变时,当你确实需要改变product时,有一些措施可以最小化问题。

3.8.1进化中的Classes

的类时,可能会出现问题,因为这些类的实例一般都是持久化的。因为改变product 类,意味着旧类中创建的实例将在新类中应用;如果你大幅度的改变类的内容,可能破坏现存的实例。目前由三种方式可以帮你解决这个问题

方法一:最简单的方法是为新加属性提供默认值。例如,如果你的类的最近的版本需一个improved_spam 实例属性,而早点的版本仅有spam属性,你可能希望在新类中定义一个improved_spam 类属性,这样你的旧的对象仍可用。你可能把improved_spam 设置为None,在用此属性的方法中,你可能不得不考虑它可能是None,例如:

setstate,但是,这是最复杂和最容易出错的。

方法三:创建一方法来更新旧的实例,子后可以手动调用实例的方法来刷新它们。注意,这需要实例函数正常工作且能用ZMI来访问。

当你在开发product时,不需太关心这些细节,因为你总是可以删除旧的实例并引进新的类。然而一旦你发布了product,其它的人开始使用它,你需要永久性的更新一下。

另一个比较麻烦的问题可能是由重命名product类引起的。重命名类会破坏所有存在的实例,所以应尽量避免,如果你真的需要改变名字,用别名。当然,改变你的类的基类则不会引起这些问题。

3.8.2 进化中的Interfaces

尽量不要修改接口。当你自己使用时你可以随便改接口。但一旦你把接口设置为公共的,那么就不应该再改变它了。因为让用户修改接口来适公共接口的变化这是不公平的。一个接口是一个约定,它标明了如何使用组件和如何执行不同类型的组件,当接口在使用或执行时,不管是用户还是开发者,改变它都会出现问题。

通常的解决方法是,首先是创建一些简单的接口,当需要改变现存的interface时也要创建新接口,如果新接口与现存的接口兼容,你可以用新接口扩展旧接口,如果新接口代替旧interfaces而不是扩展它,你需要给新接口一个新的名字,如WidgetWithBellsOn.除了新接口,你的components应当继续支持旧接口。

3.9 结论

products中,此过程需要很多步骤,也有很多细节需要注意。不过,如果你按照本章的说法,可以成功达到目的。

随着Zope的发展,我们将简化Zope开发模型,我们希望从product开发中除去大量的管理界面的细节,也希望能有一个更全面的组件架构来更好的利用接口。

products,对于创建web应用,是一个强有力的框架。通过创建products,可以利用Zope的特性,包括安全、可测量、通过Web管理和协作

last edited 2005-08-22 07:12:30 by ZoomQuiet