个人工具

三十分钟学会Zope3

来自Ubuntu中文

Oneleaf讨论 | 贡献2007年5月31日 (四) 09:25的版本 (新页面: == Zope3 In 30 Minutes(三十分钟学会Zope3) == ---- Author: Baiju M <baiju.m.mail AT gmail.com><br> Version: 0.1.4<br> Copyright: (C) 2005 Baiju M, Placed under GNU GPL version 2...)

(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转至: 导航, 搜索

Zope3 In 30 Minutes(三十分钟学会Zope3)


Author: Baiju M <baiju.m.mail AT gmail.com>
Version: 0.1.4
Copyright: (C) 2005 Baiju M, Placed under GNU GPL version 2, or (at your option) any later version
翻译:firehare
校正:leal
组织:ubuntu.org.cn


Contents(目录)



Important Note: I assume you are using Debian 3.1 (Sarge) or similar systems.
重要附注:我假定您正在使用Debian3.1(Sarge)或类似的系统(译注:显然也适用Ubuntu)。


Why 30?(为什么是30分钟?)


Sorry! Zope3 cannot be introduced in 10 minutes.

很抱歉!因为没法在10分钟内把Zope3介绍清楚。


And why should I ...?(为什么我要学...?)


If you are looking for a Pythonic framework for web application development, just continue reading. And I am not going to make a new definition for What is Pythonic? Smile . Here I will try to answer your "why?" questions.

如果您正在苦苦寻觅一套用于web应用开发的Pythonic框架,那么敬请继续。我并不打算对何谓Pythonic作何新解。 :-) ,本文将试图回答“为什么”的问题。


Keywords(关键词)


Python, Zope, Interface, Component, ZCML, ZMI, Adapter, View, Event, Service, Utility, Principal.


So let's start...(那么让我们开始吧...)


Zope3 is the third generation of Zope, a framework for web applications. You can download Zope 3.1 from http://www.zope.org/Products/Zope3 . To install untar Zope3 source package, then as root:

Zope3是第三代Zope,一个Web应用框架。您可以从[1]下载Zope3.1。欲安装Zope3,只需解压Zope3源包,并以root帐号执行如下命令:

# cd Zope-3.1.0
# ./configure;make;make install
译注:如果是在Ubuntu下,请按下面命令运行:
$tar -zxvf Zope-3.1.0.tgz -C /tmp
(如果是Breezy下,请安装Python2.3 Python2.3-dev等相关包,因为Zope3是基于Python2.4.1和Python2.3.5开发的,而Breezy默认是Python2.4.2,所以必须安装Python2.3的包文件了)
$./configure --prefix /opt/zope
$make
$make check
$make install

After installation you have to make an instance (don't worry! just do it). To do so:

安装完成后,您必须建立一个Zope Instance(Zope 实例,别担心!只需照作就行)。命令如下:

$ cd /usr/local/Zope-3.1.0/bin
$ ./mkzopeinstance --dir=$HOME/myzope --user=admin:secret123

To start Zope3 server, go to your instance directory, then:

要启动Zope3服务器,进入Instance目录,执行:

$ cd ~/myzope
$ ./bin/runzope

If you get a port error, check check 8080 and 8021 is already used by other programs; for the time being, just stop it. Start your browser , the open http://localhost:8080 . What you see is the Zope Management Interface (ZMI). ZMI is your Python prompt, hmm... no! Zope prompt, got it?. You can login and look around to see what's happening. If you played enough with ZMI, stop it from terminal (Control + C).

如果您遇到端口错误(port error),请检查8080和8021端口是否已被其它程序占用;若是,只需暂时终止该程序即可。启动浏览器,然后键入http://localhost:8080。映入眼帘的是Zope管理界面(Zope Management Interface ZMI)。ZMI是您的Python提示符,嗯...不!应该是Zope提示符,明白?您可以登录进去,到处点击看看。如果您玩够了ZMI,可以从终端用Control+C终止该程序。


BookMarker : Your first Zope3 app(BookMarker:你的第一个Zope3应用)


Yes! we are going to create a Zope3 application, an online book marker. Our app will display links to websites and a description for each link.

是的!我们就要开始创建一个Zope3应用,一个在线书签。我们的应用可以显示网站的链接及各链接的描述。

So, what you have to think about when you start a Zope3 project. Oh! sorry! I can't put it in one sentence, you better learn and practice Extreme Programming http://en.wikipedia.org/wiki/Extreme_programming . Anyway, after your initial design, you will write interfaces. Let us hope Python 3.0 will make it much easier. Then you will write unit tests, now your ideas become very concrete!. At last write your real code. You will be satisfied when you implement interfaces one by one and unit tests succeeds!. I have given the source code of BookMarker here: boom.tar.bz2

那么,在开始一个Zope3项目前,您得做何准备呢?哦!很抱歉!我没法一言以蔽之,您最好先学习并实践XP(极限编程,一种轻量级的软件开发过程) http://en.wikipedia.org/wiki/Extreme_programming 。总之,在您完成初步设计之后,就将开始编写接口。让我们期待Python 3.0 会让这变得容易些吧!之后开始编写单元测试,至此您的想法已非常具体!最后编写正式代码。当您一个接一个的实现接口并通过单元测试,您会拥有(前所未有的)满足感! 我在这里给出了BookMarker应用的源代码:boom.tar.bz2

Our code will be placed at $HOME/myzope/lib/python/boom

我们的代码将放在$HOME/myzope/lib/python/boom目录中

First create a file interfaces.py where we will keep our interfaces. Later we will implement these interfaces one by one, with strong support of unit testing.

首先创建一个interfaces.py文件,该文件保存我们的所有接口。稍后我们将在单元测试的强力支持下,一个一个实现这些接口。


Interfaces(接口)


Here is our interfaces.py:

我们的interfaces.py内容如下:

#!python
from zope.interface import Interface
from zope.schema import Text, TextLine, Field

from zope.app.container.constraints import ContainerTypesConstraint
from zope.app.container.constraints import ItemTypePrecondition
from zope.app.container.interfaces import IContained, IContainer

class IMark(Interface):
"""This is the book mark object."""

url = TextLine(
title=u"URL/Link",
description=u"URL of the website",
default=u"http://www.zope.org",
required=True)

description = Text(
title=u"Description",
description=u"Description of the website",
default=u"",
required=False)

class IBookMarker(IContainer):
"""This is the container for all book marks."""

name = TextLine(
title=u"Name of BookMarker",
description=u"A name for BookMarker",
default=u"",
required=True)

def <u>setitem</u>(name, obj):
pass

<u>setitem</u>.precondition = ItemTypePrecondition(IMark)


class IMarkContained(IContained):
"""A book mark can only contain in a BookMarker"""

<u>parent</u> = Field(
constraint = ContainerTypesConstraint(IBookMarker))

Our first interface IMark has two attributes, one is the URL of the site and the other one is the description. Please note, IMark is not a class even though we used Python's class definition. We inherited from Interface to make it an interface. Second one is a container interface, which is an extended IContainer interface. By using this container interface we can persist our data (instances of IMark implementations). We will put all objects of IMark in a container object of IBookMarker. We will implement IMark along with IMarkContained as a constraint interface. So that IMark object will be only contained in an IBookMarker object.

我们的第一个接口IMark有两个属性,一个是站点的URL,另一个是它的描述。请注意,尽管我们使用了Python的类定义,但IMark并不是一个类。IMark是个接口,继承自Interface。第二个是个容器接口,它是一个扩展后的IContainer接口。我们可以使用这个容器接口来保存数据(IMark实现的实例)。我们会把所有IMark类型对象都放到IBookMarker类型的容器对象里。我们实现IMark的同时会把IMarkContained作为约束接口,所以IMark对象只能包含在IBookMarker对象中。


Unit Testing(单元测试)


Now create tests.py and put the following code there:

现在创建tests.py文件,并输入下列代码:

#!python
import unittest
from zope.testing.doctestunit import DocTestSuite

from zope.app.container.tests.test_icontainer import TestSampleContainer

from boom.bookmarker import BookMarker, Mark


class BookMarkerContainerTest(TestSampleContainer):

def makeBookMarkerObject(self):
return BookMarker()

def test_suite():
return unittest.TestSuite((
DocTestSuite('boom.bookmarker'),
unittest.makeSuite(BookMarkerContainerTest),
))

if <u>name</u> == '<u>main</u>':
unittest.main(defaultTest='test_suite')

Actually, we are not written any unit tests here, but this will make our doc tests working automatically.

实际上,这里我们并没有编写任何单元测试,不过它会自动对我们的文档进行测试。

To run the unit test:

然后运行单元测试:

$ cd $HOME/myzope/lib
$ ../bin/test -vpu --dir boom

Real coding!(正式编码)


Now let's move on to the implementation (bookmarker.py):

现在让我们开始实现前面定义的接口(bookmarker.py)

#!python
<u>docformat</u> = 'restructuredtext'

from zope.interface import implements
from zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained

from boom.interfaces import IMark, IMarkContained, IBookMarker

class Mark(Contained):
"""Implementation of IMark

Make sure that the `Mark` implements the `IMark` interface::

>>> from zope.interface.verify import verifyClass
>>> verifyClass(IMark, Mark)
True

Make sure that the `Mark` implements the `IMarkContained` interface:

>>> from zope.interface.verify import verifyClass
>>> verifyClass(IMarkContained, Mark)
True

An example of checking the url of Mark::

>>> mk = Mark()
>>> mk.url
u'http://www.zope.org'
>>> mk.url = u'http://www.python.org'
>>> mk.url
u'http://www.python.org'

An example of checking the description of Mark::

>>> mk = Mark()
>>> mk.description
u''
>>> mk.description = u'Zope Project Web Site'
>>> mk.description
u'Zope Project Web Site'
"""

implements(IMark, IMarkContained)

url = u"http://www.zope.org"
description = u""


class BookMarker(BTreeContainer):
"""Implementation of IBookMarker using B-Tree Container

Make sure that the `BookMarker` implements the `IBookMarker` interface::

>>> from zope.interface.verify import verifyClass
>>> verifyClass(IBookMarker, BookMarker)
True

An example of changing the name of BookMarker::

>>> bm = BookMarker()
>>> bm.name
u''
>>> bm.name = u'MyBookMarker'
>>> bm.name
u'MyBookMarker'
"""

implements(IBookMarker)

name = u""

We have written doctests along with the implementations. Doctests are accompanied with examples, so it is called example driven unit testing.

我们在编写实现的同时已顺带写了Doctests,该Doctests还伴有示例,因此也被称为实例驱动的单元测试:


Configuration(配置)


Now configuration (save in configure.zcml):

现在编写配置(保存在configure.zcml文件中):

<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">

<interface
interface=".interfaces.IBookMarker"
type="zope.app.content.interfaces.IContentType"
/>

<content class=".bookmarker.BookMarker">
<implements
interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
/>
<implements
interface="zope.app.container.interfaces.IContentContainer"
/>
<factory
id="boom.bookmarker.BookMarker"
description="Book Marker"
/>
<require
permission="zope.ManageContent"
interface=".interfaces.IBookMarker"
/>
<require
permission="zope.ManageContent"
set_schema=".interfaces.IBookMarker"
/>
</content>

<interface
interface=".interfaces.IMark"
type="zope.app.content.interfaces.IContentType"
/>

<content class=".bookmarker.Mark">
<implements
interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
/>
<factory
id="boom.bookmarker.Mark"
description="A book mark."
/>
<require
permission="zope.ManageContent"
interface=".interfaces.IMark"/>
<require
permission="zope.ManageContent"
set_schema=".interfaces.IMark"
/>
</content>

<browser:addform
label="Add Book Marker"
name="AddBookMarker.html"
schema="boom.interfaces.IBookMarker"
content_factory="boom.bookmarker.BookMarker"
fields="name"
permission="zope.ManageContent"
/>

<browser:addMenuItem
class=".bookmarker.BookMarker"
title="Book Marker"
permission="zope.ManageContent"
view="AddBookMarker.html"
/>

<browser:editform
schema="boom.interfaces.IBookMarker"
for="boom.interfaces.IBookMarker"
label="Change Book Marker"
name="edit.html"
permission="zope.ManageContent"
menu="zmi_views" title="Edit"
/>

<browser:containerViews
for="boom.interfaces.IBookMarker"
index="zope.View"
contents="zope.View"
add="zope.ManageContent"
/>

<browser:addform
label="Add Mark"
name="AddMark.html"
schema="boom.interfaces.IMark"
content_factory="boom.bookmarker.Mark"
fields="url description"
permission="zope.ManageContent"
/>

<browser:addMenuItem
class="boom.bookmarker.Mark"
title="Mark"
description="URL of Website"
permission="zope.ManageContent"
view="AddMark.html"
/>

<browser:editform
schema="boom.interfaces.IMark"
for="boom.interfaces.IMark"
label="Change Mark"
fields="url description"
name="edit.html"
permission="zope.ManageContent"
menu="zmi_views" title="Edit"
/>

<browser:page
name="marks.html"
for="boom.interfaces.IBookMarker"
class=".browser.BookMarks"
template="marks.pt"
permission="zope.Public"
menu="zmi_views"
title="Marks"
/>

</configure>

Is it self explanatory? "no...!" then ok! we will discuss Zope Configuration Markup Language (ZCML) briefly later. Actually, if you are familiar with ZCML this configuartion will be more than self explanatory. It will give you an overall idea about the entire application. Now you might think, it is not Pythonic Sad Hey! think twice!.

它是不言自明(即能够自我解释,XML之类的标记语言都有这个特点)的吗?“不...!”好吧,我们稍后会简单介绍Zope Configuration Markup Language(ZCML,Zope配置标记语言)。实际上,如果熟悉ZCML的话,你会发现这个配置不止是不言自明,它还能让你对整个应用有一个总体的感觉。至此你或许会迷惑不解,这并非Pythonic嘛 :-(。嗨!三思之!


Just run it


As the last step to work our application, put the following line in:$HOME/myzope/etc/package-icludes/boom-configure.zcml:

最后一步,让我们的应用运行起来,在文件$HOME/myzope/etc/package-icludes/boom-configure.zcml中插入下列行:

<include package="boom"/>

Now you registered your package.

现在你已经注册了boom包。

Run zope again, then open your browser, add a BookMarker and few book marks.

重新启动Zope,打开浏览器,添加一个BookMarker和一些书签。

Now you want to arrange your your book marks in a better way, don't you?. For the time being, just relax, then we will create a view for book marks.

现在,你不想让你的书签排列得更好看吗?先稍稍放松一下,之后我们将为书签创建一个视图。


Views(视图)


Now create a file named browser.py with following code:

现在新建一个名为browser.py的文件,并输入下列代码:

#!python

from boom.interfaces import IMark

class BookMarks:

def <u>init</u>(self, context, request, base_url=''):
self.context = context
self.request = request
self.base_url = base_url

def listMarks(self):
marks = []
for name, child in self.context.items():
if IMark.providedBy(child):
info = {}
info['url'] = child.url
info['description'] = child.description
marks.append(info)
return marks

Then one template (marks.pt):

然后创建一个模板(marks.pt)

<nowiki>
<html metal:use-macro="views/standard_macros/view">
<body>
<div metal:fill-slot="body">

<div class="row">
<div class="label">Book Marks:</div>
<br/><br/>
<li tal:repeat="item view/listMarks">

<a href="" tal:attributes="href item/url">
<span tal:content="item/url">Link</span>
</a>
<pre tal:content="item/description">Description


</li> </div>

</div> </body> </html> </nowiki></pre>

Now by clicking on "Marks" tab you can see all book marks.

现在点击一下“Marks”标签,你就可以看到所有书签了。

Ok! this is not the end, just the beginning of your study.

好的!不过还没完,这只是你学习之路的开始。


Functional testing(功能测试)


Let's finish our example writing a functional test for view (ftests.py):

让我们为视图编写一个功能测试(ftests.py),为我们的例子画上一个句号。

#!python

import unittest
from zope.app.testing.functional import BrowserTestCase

class BookMarksTest(BrowserTestCase):

def testMarksListing(self):
pass


def test_suite():
return unittest.TestSuite((
unittest.makeSuite(BookMarksTest),
))

if <u>name</u> == '<u>main</u>':
unittest.main(defaultTest='test_suite')

To run the functional test:

要运行功能测试,执行:

$ cd $HOME/myzope/lib
$ ../bin/test -vpf --dir boom

Now what?(接下去该干吗?)


Now you can start learning Zope3 in detail, using Zope3 book. Also join zope3-users mailing list.

接下来,你可以找本Zope3书籍开始详细学习Zope3了。还有加入zope3-user邮件列表。

There is a good Zope3 quick start guide by Benji York: http://www.benjiyork.com/quick_start/

Benji York写了一个不错的Zope3快速入门指南,网址为: http://www.benjiyork.com/quick_start/

A good introductory book is also available in print, visit: http://worldcookery.com/

还有一本已出版的介绍性图书,很不错,请访问: http://worldcookery.com/

Just one more thing: I want to improve this document, so don't hesitate to write your feedback to: baiju.m.mail AT gmail.com

还有一点:我想不断完善这份文档,因此有何意见/建议千万别犹豫,请反馈至: baiju.m.mail@gmail.com


Hey! What's time now?(嗨!现在什么时候了?)


Oh! it's only 10 minutes since we started reading this article. We got 20 more minutes to explain what's happened here. So let's look back again.

哦!从开始阅读这篇文章到现在才花了10分钟。我们还有20分钟的时间来解释前面讲过的内容。那么让我们踏上回顾之旅吧。


Installation and Configuration(安装和配置)


You can download Zope 3.1.0 or later for your major works. Install Zope3 as root, though it is not necessary. When you experiment with Zope3, make instance as a normal user. For production systems, you get the additional advantage of OS level security. Since we manually installed Zope3 (as root), the default installation path will be /usr/local/Zope-3.1.x . When making zope instance, you have to specify zope manager's user name and password. You can make more instances, if required.

你可以下载 Zope 3.1.0 或更新版本用于大部分工作。以root权限安装 Zope3,当然这并非必需。当你用开始试验 Zope3 时,可以普通帐号来创建实例。对于产品系统而言,你可以充分利用操作系统级安全。由于我们以root权限安装 Zope3 ,因此默认安装路径是 /usr/local/Zope-3.1.x。当创建 Zope 实例时,你还需指定 Zope 的管理用户名和密码。如有必要,你可以创建更多实例。

In your Zope 3 instance directory, there are few directories with specific purposes. Here ownwards I will be using $ZOPE3INSTANCE to refer your instance directory

在你的 Zope 3 实例目录中,有一些特定用途的目录。此后,我会用 $ZOPE3INSTANCE 表示你的实例(instance)目录

$ZOPE3INSTANCE/etc In 'etc' you can see some configuration files. In $ZOPE3INSTANCE/etc/zope.conf you can edit port numbers of http and ftp servers.

在 'etc' 目录里你可以找到一些配置文件。在 $ZOPE3INSTANCE/etc/zope.conf 里你可以编辑 http 和 ftp 服务器的端口号。

$ZOPE3INSTANCE/var Zope saving all data here. Backup this directory regulary. If 'Data.fs' is missing, it will be automatically created when you run zope again.

Zope 将所有数据保存在这个目录内。请定期备份该目录。如果 'Data.fs' 文件遗失,在你再次运行 Zope 时会自动创建该文件。

$ZOPE3INSTANCE/bin Few utility scripts. 'runzope' and 'test' are already familiar to you. 'pyskel' script will be very useful for creating template codes from interfaces, Example:

一些实用脚本。 如你已熟知的 'runzope' 和 'test'。'pyskel' 脚本也很有用,它可以从接口创建模板代码,如:

$ZOPE3INSTANCE/bin/pyskel boom.interfaces.IMark > file.py

$ZOPE3INSTANCE/lib/python As I said earlier you can place your Zope3 packages here. By default this won't be in your Python path. You can also place your package in any standard Python path.

如我之前所述,你可以把自己的Zope3包存放在上述目录中。默认情况下,这个目录不会在你的 Python 路径里。你也可以将自己的包放在任何标准的 Python 路径里。


Why should I code like this?(为什么我要这样编写代码呢?)


When we started discussing BookMarker, the first word I coined is Extreme Programming (XP). I strongly recommend you to read about Extreme Programming. It will really influence you to write code in Zope3 way (directly and indirectly). Ok, one causion: many XPers believe that frameworks are bad. Here, I can not give an answer in one sentence, so you find out yourself. "Extreme Programming Explained" by Kent Beck will be a good starting point for your study. By the way, another classic book which you can read is "Design Patterns" by Gang of Four. In this book they say : 'Program to an interface, not to an implementation'. To simulate a formal definition of interfaces in C++, they used classes with virtual functions. Just like this, in Python we will use zope.interface.Interfce inherited metaclass for defining an interface. There is every chance for an 'interface' concept in Python language by version 3.0 . According to Extreme Programming: 'The four basic activities of development are coding, testing, listening, and designing.' Zope3 makes your software testing, a breeze. You can write unit and functional tests very easily.

当我们开始讨论书签时,我提出的第一个词是极限编程(XP),我强烈建议你去看看极限编程的相关内容。它能够真正影响你,让你以 Zope3 的方式(直接或间接的)去编写代码。OK,还有个提醒:许多极限编程人员都认为框架是不好的。这儿我无法一言以蔽之,请你自已寻找答案。 Kent Beck的《极限编程精解》是学习极限编程的不错的起点。另外,你还可以阅读另一本经典书籍,就是 Gang of Four (译注:GoF戏称为“四人帮”,因该书有四位作者而得名)的《设计模式》。在这本书里他们主张:“针对接口而非实现进行编程”。为了在C++里模仿接口的形式化定义,他们使用了带虚拟函数的类(译注:因为C++没有interface这一关键词)。与此相仿,在 Python 中我们会用继承自 zope.interface.Interfce 的metaclass来定义接口。在Python语言3.0版本出来之前,Python里的“接口”概念可用多种方式进行模拟。根据极限编程的说法:“开发的四个基本活动就是编码,测试,聆听和设计” 。软件测试对 Zope3 来说小菜一碟,单元测试和功能测试编写起来非常容易。


Let's look into interfaces(让我们研究接口)


I hope you are familiar with the concept of interfaces. Anyway, when we speak about an interface, we meant it to use with reference to an object (i.e, an instance of a class). For example if 'A' is a class which implements 'IA', and 'a' is an instance of 'A', then 'IA' is the interface of 'a', got it? But normally we only deals with the interface and its implementing class.

但愿你已熟悉接口的概念。总之,当我们论及接口时,其意就是引用一个对象(即一个类的实例)之用。例如如果“A”是一个类,实现了“IA”,“a”是一个“A”的实例,那么“IA”就是“a”的接口,明白了吗?但通常我们只涉及接口和其实现类。

In our interfaces.py we defined three interfaces. The first interface 'IMark' defines a book mark object. A book mark has two attributes, one is the url and another one is the description. We used schemas available at zope.schema package to specify these attributes.

在 interfaces.py 文件里,我们定义了三个接口。第一个接口“IMark”定义了一个书签对象。一个书签有两个属性,一个是 url 而另一个是 description(描述说明之意)。我们使用了zope.schema 包提供的schema来规定这些属性。

As we mentioned earlier IBookMarker is a container interface. We extended IContainer interface with one name attribute. Also we put one item type pre-condition. So IBookMarker object can only contain an IMark object. Now before moving to the next section, please note from which packages and modules we imported different classes/interfaces. Just open the sources of those packages, and see how well documented they are!. Some documentation are written in seperate ReStructuredText files with unit testing, this is the Zope3 way of unit testing.

正如我们先前提到的,!IBookMarker是一个容器接口。我们扩展了带一个name属性的 IContainer 接口。我们放入一个类型为 pre-condition 的项。因此 IBookMarker 对象就只能包含一个 IMark 对象了。在进入下一节之前,请注意我们从哪个包和模块中导入不同的类/接口。打开这些包的源代码,看看它们的文档注释何其完善。一些文档被写在带单元测试的独立 ReStructuredText 文件中,这些都是 Zope3 风格的单元测试。


Unit testing re-visited(再论单元测试)


We wrote our test in a file named tests.py. You can also write tests in a package named tests. All test modules under this package should have test_ prefix. We also automated our doctests written along with implementation. To test our !BookMarker container, we inherited TestSampleContainer. For testing containers, you can stick with unittest module. Also use it where you want more reusablity. Anyway, we will integrate all doctests with unittest module. This will help us to run tests automatically, from a single point.

我们在文件 tests.py 中编写我们的测试。你也可以在 tests 包中编写测试。所有在该包中的测试模块将有一个 test_ 的前缀。我们也与实现一起自动进行我们的 doctests。为了测试我们的 !BookMarker 容器,我们继承了 TestSampleContainer。为了测试 containers,你可以加入 unittest 模块。你也可以在你其他需要重用的地方使用它。无论如何,我们将用 unittest 模块集成所有的 doctests。这将帮助我们从单一的点开始自动进行测试。


Let's talk about implementations(让我们讨论下实现)


In the first line of bookmarker.py we set a special variable attribute <u>docformat</u> = 'restructuredtext'. Our documentation strings are written in ReStructuredText format. I strongly reccomend you to use ReST for all kinds of Python documentations. (This article is written in ReST: svn co svn://svn.berlios.de/zissue/trunk/z3in30m).

在 bookmarker.py 文件的第一行,我们设置了一个特殊的可变属性 <u>docformat</u> = 'restructuredtext'。我们的文档字符串是用 ReStructuredText 格式写的。我强烈建议你在 Python 所有类型文档中都用 ReST。(本文的 ReST 格式在:svn co svn://svn.berlios.de/zissue/trunk/z3in30m)

First we imported implements function from zope.interface package. Using this function we can say a class implements one or more interfaces. BTreeContainer is full implementation of IContainer interface. We inherit it to implement our Container interfaces. Similarly Contained is an implementation of IContained. Mark class implements both IMark and !IMarkContained. IMarkContained is an extended interface of IContained. So by inheriting Contained class we get a partial implementation of our interfaces. Now the remaining things to implement is two attributes, url and description. Similarly majority of IBookMarker is implemented in !BTreeContainer. I hope documentation strings are self explanatory.

首先,从 zope.interface 包中导入实现函数。借助该函数,我们可以让一个类实现一个或多个接口。BTreeContainer 是 IContainer 接口的完整实现。我们继承它以实现自己的 Container 接口。同样 Contained 是 IContained 的实现。Mark 类实现了 IMark 和 IMarkContainedIMarkContained 是个 IContained 的扩展接口。因此通过继承 Contained 类,我们可以获得IMarkContained接口的部分实现。至此余下只要实现两个属性url和description即可。类似的,IBookMarker 的大部分功能已在 BTreeContainer 中实现。我想其中的文档字符串足以让你明了一切。


ZCML Explained(ZCML 说明)


Let me ask one question, which you are going to face many times later. Do you think a Programming language should be used to write configuration files? If yes, why?. Why we can not use a text files with some conventions or markups.

让我先来问个问题,今后你打算更频繁的面对什么呢?(译注:代码还是外在的配置文件?大量的初始化、配置参数是该hardcoded在代码中还是放在独立的配置文件里?)你认为编程语言应该用来编写配置文件吗?如果是的话,理由何在?为什么我们不能用有一定规范或标记的文本文件呢?

Anyway, ZCML is the XML based configuration system for Zope3. The base tag 'configure' specifies namespaces to use. In our configuration we used two namespaces, 'zope' and 'browser'. 'zope' namespace contains the basic elements required to register our content objects. 'browser' is for view related configuration.

总之,ZCML是 Zope3 基于 XML 的配置系统。根标记(base tag)“configure”规定所用的名字空间。在上述配置中,我们使用了两个名字空间,“zope”和“browser”。“zope”名字空间包括注册content对象所要求的基本元素,而“browser”则用于view相关的配置。

The first tag we used is 'interface'. It is called a directive. In our configuration 'iterface' is a simple directive and 'content' is a complex directive.

我们用的第一个标记是“interface”,称为指令(directive)。在上述配置中,'iterface'是一个简单指令,'content'是一个复合指令。


Views and ZPT(视图和 ZPT)


Your objects are finally saved in ZODB, you may choose other storage mechanisms also. In zope you can present your objects in different ways. I mean, through different protocols like http, ftp, xmlrpc etc. In our case, we created a view for browser (yes, through http). We put all logics for presentation in browser.py. And created a Zope Page Template (ZPT) for real presentation. Normally you should avoid any information retrieval logic in ZPT.

我们的对象最终被保存在 ZODB中,你也可以选择其他存储机制。 在 zope 里你可以用不同的方式来呈现自己的对象。我的意思是,通过不同的协议如 http,ftp,xmlrpc等。在上述示例中,我们为浏览器(是的,通过 http)创建了一个视图。我们把呈现(presentation)相关的所有逻辑放在 browser.py 文件中,并为实际呈现创建了一个 Zope 页面模板(ZPT)。一般来说,你应避免把任何信息获取的逻辑放在 ZPT 中。


The things we didn't mentioned(我们没有提及的事物)


Please go to the last section, otherwise you can not finish this article in 30 minutes Smile

径直去看最后一节吧,不然就没法在30分钟之内看完这篇文章喽 Smile

Of course, in an introductory document we can only cover a fraction of the whole technology. Here I have omitted many things for various reasons.

毫无疑问,在一篇介绍性的文章中我们只能提及整个技术的一部分。出于多种原因,本文我未论及很多东西。

In the beginning, I said just one assumption about you. I really meant many other things. Surely you should be a Python programmer. You should know basic administration. Basic understanding of web technologies. And ofcourse, willing to spend time Smile

本文一开始,我对读者只做了一个假定,实际上并非仅此而已。显然你应该是个Python程序员,应该懂得基本的系统管理,基本理解 Web 技术,当然还有就是愿意花时间 Smile

While installation you might get error due to Python development libraries not installed. If you know Python and system administration you will just run: apt-get install python-dev Similary you have created <u>init</u>.py file to make our package working.

安装时,你或许会因未安装 Python 开发库而碰到错误提示。如果熟悉 Python 和系统管理,只需运行:apt-get install python-dev 类似的,你会创建 <u>init</u>.py 文件以便我们的包可以正常工作。

If you are interested in Zope3 by now, surely you will explore more in future. While you exploring, you will see that doctests can be written in stand alone text files. Similarly you will understand lots of other things.

如果至此已对 Zope3 感兴趣的话,相信你今后会作更多探索。在探索过程中,你会发现 doctests 可以写在独立的文本文件中。此外,你也会理解很多其它东西。

One thing I can assure you is that zope is really a matured framework. It has almost 9 year history of successfull running. Many technologies evolved through zope. Infact zope and zope developers has influenced Python language itself. Yes! it is one of the gratest Python application ever written.

我可以向你保证, Zope 是个真正成熟的框架。它已经有将近 9 年的成功运行史。许多技术都通过 zope 得以改善。事实上 zope 和 zope 开发人员已经影响了 Python 语言本身。不错,它是有史以来最伟大的 Python 应用之一。


The End(结束语)


Oh! it is just the end of this article. And the great beginning of your journey through Zope3 world. So, good luck.

哦!这只是这篇文章的结束,却是你在 Zope3 世界之旅的开始。那么,祝你好运!


About the author(关于作者)


I am Python programmer from Kerala. I love Python. Previously I have worked for Malayalam i18n & l10n in free softwares. I have worked for Free Software Foundation of India (as a job). I was a Koha consultant for some time. Currently I am doing lots of Python, PyGTK and PostgreSQL (about one and half years). I am a prod GNU Emacs user.

我是个Python程序员,来自 Kerala 。我热爱 Python。以前我致力于自由软件里 Malayalam语 的 i18n & l10n 化。我也为印度自由软件基金会工作(作为一份工作),有段时间我是个 Koha 顾问。目前我主要使用 Python,PyGTK 和 PostgreSQL (大约有一年半的时间)。我是一个 GNU Emacs 用户。