麦田守望者's profile异想空间PhotosBlogLists Tools Help

Blog


    8/27/2009

    IATTopic.queryCatalog

    IATTopic接口声明了queryCatalog方法:

    def queryCatalog(REQUEST=None, **kw):
    """Invoke the catalog using our criteria to augment any passed
    in query before calling the catalog.
    """

    利用这个方法,我们能够以编程的方式控制提供了IATTopic接口的对象的搜索行为。最典型的是Plone的标准内容类型Collection,在更早期的Plone版本中其称作Smart Folder。Collection这个名字可以看作是面向用户的名字,非常清晰直观的反映了它的功能。在Plone内部,Collection类型实际上是一个ATTopic类,其portal_type是Topic,archetype_name是Collection。言归正传,看一看能用这个接口方法做什么。

    在ATTopic类实现中,丰富了queryCatalog方法的参数:

    def queryCatalog(self, REQUEST=None, batch=False, b_size=None,
    full_objects=False, **kw):
    pass

    利用这些参数,能完成如下任务:

    1、在已经设置了搜索条件的基础上,附加其它额外的条件。将任何额外的搜索条件,按照ZCatalog的规范组合成一个字典对象,传递给kw参数。关于ZCatalog的参考,《The Zope2 Book》的Searching and Catagorizing Content章节有详细的介绍。

    2、按批次返回特定数量的对象集合,即分页。batch参数指明是否按批次返回搜索结果,b_size说明返回的结果集的大小。除了这两个参数,还需要在context.REQUEST对象中设定b_start。b_start指明,在完整的搜索结果结合中,从第几个对象开始返回b_size数量的对象集合。和数组的下标一样,b_start的值从0计起。

    在这种情况下,queryCatalog方法返回的是一个 ZTUtils.Batch.Batch对象。Batch对象实现了__getitem__和__len__方法。同时,还提供了previous和 next属性,用于前后双向跌代下一个Batch对象。如果到头了,则previous和next会相应的被置为None。

    3、返回的对象集合中,包含每一个完整的对象。full_objects参数指明,调用每一个Brain对象的getObject方法,从ZODB中获取完整的对象。此种做法可能会影响Plone的运行性能。

    举个例子:

    在当前上下文中存在一个Collection对象,其ID为search。想要搜索EffectiveDate在2009年1月1日以来的Page对象,并且按照EffectiveDate排序,显示头10个对象。

    from DateTime import DateTime
    qc = {}
    qc['portal_type'] = 'Document'
    qc['effective'] = { 'query': DateTime('2009/1/1'), 'range': 'min' }
    qc['sort_on'] = 'effective'
    qc['sort_limit'] = 10
    qc['sort_order'] = 'descending'
    context.search.queryCatalog(**qc)[0:10]

    如果想要分页显示所有Page对象,每一页显示20个,显示第2页:

    qc = {}
    qc['portal_type'] = 'Document'
    qc['sort_on'] = 'effective'
    qc['sort_order'] = 'descending'
    # 这一行很重要。如果缺少这一行,则会始终从搜索到的第一个对象开始返回结果
    context.REQUEST.set('b_start', (2 - 1) * 20)
    context.search.queryCatalog(batch=True, b_size=20, **qc)
    7/31/2009

    解决psycopg2导入错误

    psycopg2版本:2.0.11

    Zope版本:2.10.7-final

    在上述环境中创建一个ZPsycopgDA数据连接对象的时候,会出现ImportError异常,提示psycopg version mismatch (imported 2.0.11 (dt dec ext pq3))。

    解决办法:在ZPsycopgDA目录中,修改DA.py文件的119行:

    - if psycopg2.__version__[:5] not in ALLOWED_PSYCOPG_VERSIONS:
    + if psycopg2.__version__.split(' ')[0] not in ALLOWED_PSYCOPG_VERSIONS:

    导致这个错误的原因是,2.0.11版本的psycopg2的__version__属性会返回“2.0.11 (dt dec ext pq3)”,只有按照空格打断字符串并取得第一元素,才能正确获得版本号。


    7/30/2009

    解锁Plone对象

    如果某个对象被上了锁,导致没法对其进行操作,可以用wl_clearLocks方法为其解锁:

    obj = getattr(context, 'obj_id')
    obj.wl_clearLocks()

    至于对象为何以及在什么条件下会被上锁,我尚不清楚。如果您清楚,感谢指点一二。

    7/29/2009

    content_status_modify方法在哪里定义的?

    寻寻觅觅,在源码中始终不见content_status_modify方法的踪迹。你知道吗?请告诉我。谢谢!

    BaseFolder对象的manage_addFolder方法

    BaseFolder位于Products.Archetypes.BaseFolder.py

    在Python脚本对象中,可以使用manage_addFolder方法创建一个Folder对象。从ATFolder继承下来的容器对象,都包含了这个方法。当在自定义的容器对象上调用manage_addFolder方法的时候,要明确地给type_name参数传递一个字符串值Folder。例如:

    context.manage_addFolder(id = 'objid', title = 'Object's title', type_name = 'Folder')

    然而,不要被这个方法的字面意思所蒙蔽。只要给type_name参数传递了正确的portal_type值,还可以用它创建其他类型的内容对象。例如:

    context.manage_addFolder(id = 'objid', title = 'title', type_name = 'Document')
    context.manage_addFolder(id = 'objid', title = 'title', type_name = 'Image')

    这里“正确的”含义有二。一是,type_name的值必须是已经注册的对象的portal_type值;二是,指定的portal_type必须是当前容器被允许容纳的对象类型中的一种。

    实际上,manage_addFolder在做了一系列准备工作后调用invokeFactory方法,而invokeFactory最终调用portal_types对象的constructContent方法创建对象。如果很清楚自己要做些什么,也可以直接调用invokeFactory和constructContent方法。

    7/22/2009

    IObjectManager接口中的几个有用的方法

    IObjectManager位于OFS.interfaces.py文件中。IObjectManager接口定义了一个容器类需要实现的方法。其中有几个方法很有用。

    def hasObject(id):
        """ Indicate whether the folder has an item by ID. """

    def manage_delObjects(ids=[], REQUEST=None):
        """Delete a subordinate object

           The objects specified in 'ids' get deleted.
        """

    def __getitem__(key):
        """
        """

    • hasObject方法接受一个参数,该参数表示某个对象的id,hasObject方法会判断该对象是否存在于容器中。
    • manage_delObjects方法用于在容器中删除一组对象。删除的依据是ids参数,这是一个列表对象,其中包括将要被删除的对象的id。
    • __getitem__方法使得提供了IObjectManager接口的对象可以像字典对象那样获得容器中的某个对象。

    IObjectManager接口还提供了诸如superValues、objectItems、objectValues等其他方法用于访问容器中的对象。

    Plone的ATFolder对象通过继承和实现IATFolder接口,也提供了IObjectManager接口的功能。因此,在Plone中,以编程的方式对一个ATFolder对象施加更多的控制就变得容易许多。通过对CMFCore和CMFPlone的探索得知,还有许多其他更高层的接口可以利用。

    7/12/2009

    在portal_catalog中按照分类搜索使用Subject关键字

    当以编程方式通过portal_catalog工具搜索具有特定分类属性的内容对象的时候,使用Subject关键字。请注意首字母大写。在ZMI中,portal_catalog的Indexes页中存在一个类型为KeywordIndex,名称为Subject的索引。这就是我们所需要的。

    7/11/2009

    (dynamic view)和(selected layout)

    Plone提供了一种机制,允许开发者给实现了IATFolder接口的内容类型提供不同的显示视图(Views),而用户则可以通过Display菜单设置内容类型的动态视图。作为内容类型的开发者,特别需要留意“(dynamic view)”和“(selected layout)”的使用。即在某个内容类型的GenericSetup配置文件中,必须确保下面的两行正确出现:

    <alias from="(Default)" to="(dynamic view)" />
    <alias from="view" to="(selected layout)" />

    如果,选择Display菜单中的视图没有任何作用的话,那么可以看看这两个配置值是否正确出现。


    5/5/2009

    理解Browser View之多适配器

    视图组件是命名的多适配器。其作用于的对象是HTTP Request对象和提供某个特定接口的对象实例。在视图组件的configure.zcml文件中声明page的时候,page元素就描述了这一概念。例如:

    <browser:page
      for="..interface.IReport"
      class="report_view.py"
      name="view"
      template="report_view.pt"
      permission="zope2.View"
    />

    属性name指出,我们声明了一个名字叫做view的视图。for指出只有当请求一个提供了IReport接口的对象的时候,才会调用这个视图。当然,发出请求的用户必须具有permission属性指定的权限才行。

    用编程方式获得这个视图对象,能够更直观地体会到多适配器的概念:

    from zope.component import getMultiAdapter
    from zope.publisher.browser import TestRequest
    # 假设该Report类实现了IReport接口
    from myproject import Report

    report = Report()
    request = TestRequest()
    view = getMultiAdapter((report, request), name=u"view")
    view()



    4/24/2009

    自定义内容类型的Title

    基于Archetype框架开发内容类型,由于它们继承自BaseContent或者ATContentType,因此自然也就提供了IMinimalDublinCore接口。该接口中定义了Title方法,用于获取内容类型对象的title值。这样,自定义内容类型的Title就非常轻松了。示例代码如下:

    from Products.ATContentTypes.content.base import ATCTContent
    from Products.CMFCore import permissions
    from AccessControl import ClassSecurityInfo

    class MyContent(ATCTContent):
    """ Demo content type for demonstrating
    how to custom this content type's Title
    """

    security = ClassSecurityInfo()

    security.declareProtected(permissions.View, "Title")
    def Title(self):
    """ return the custom title """
    return "My custom title"

    该示例代码省略了部分与主题无关的内容。有一点需要留意,即一定要给Title方法声明保护级别。

    2/23/2009

    吼一嗓子,Zope文档有更新了

    其实也没什么可多说的。《The Zope Book》和《The Zope Developers Guide》终于有重大更新了。请留意Zope.org中的Documentation部分。

    2/19/2009

    自定义Plone的重要概念

    在《Professional Plone Development》一书的第四章中有一句话,对于理解最新的Plone开发技术和自定义Plone的方法有着非常重要的作用。它是:

    Zope 3’s concept of customization by interfaces is an evolution of Zope 2’s concept of customization by location and CMF’s concept of customization by skin layer.

    Zope 3的自定义概念依靠接口(interface),Zope 2的自定义概念依靠位置,而CMF的自定义概念则依靠skin layer。Zope 3的自定义概念是具有革命性的。

    这句话同样揭示了Zope 3的精髓之一,针对接口编程。尽管现有版本的Plone仍旧构建于Zope 2之上,但是由于Five(Zope 2 + Zope 3 = Five)的存在,我们可以在Zope 2中使用Zope 3的概念和开发技术开发Plone产品。这不但可以让及时把新技术应用到实际的产品开发中,并且还可以在有朝一日全面向Zope 3平台迁移的时候,有一个平滑的迁移曲线。

    2/11/2009

    读《Professional Plone Development》的朋友们注意了

    《'Professional Plone Development': book improvements》

    作者Martin Aspeli给出的勘误。读这本书的朋友们请留意了。

    2/10/2009

    在Plone中处理大型文件(好文共赏)

    近日读到一篇好文,题目是《Large Files Management in Plone》。作者全面介绍了在Plone中管理大型文件的各种方法。文章分为两个部分:

    • Popular Products for Video Management in Plone
      1. Plone4ArtistsVideo
      2. Pumi
    • File Storage
      1. ZODB (Zope Object Database)
      2. File System
      3. External Servers

    正如第一部分的标题所示,重点介绍了两个用于管理视频文件的Plone产品。Plone4ArtistsVideo非常有名,plone.tv站点用了这个产品。Pumi则是一个产品包,还包含了其他一些实用的产品,例如ATCountry WidgetATVocabulary Manager等。

    第二部分则集中到了Plone的基础平台Zope上。列举了三个存储文件的策略。首当其冲的当然是ZODB,尽管Zope加强了对blob类型数据的支持,但是对于存储向音频、视频这样的大型二进制文件来说,ZODB就显得力不从心。

    很自然的,我们会想到为何不把这些大文件存放到物理磁盘的文件系统中呢。是啊,这样一来,管理员和开发人员可以找到很多种提高文件管理和IO性能的方法,优化站点的性能。在File System部分中,作者同样列举了几个使用的Plone产品,例如,CMFExtFilePloneExtFileExternalStorage等。

    最后,干脆就把文件放到远程文件共享站点上。而只在我们的内容对象中嵌入<embed>代码。

    以上是对《Large Files Management in Plone》的简单介绍,详细内容请阅读原文。

    最后,还可以观看视频Multimedia and Podcasting With Plone,在后面的部分也专门有介绍在Plone中管理大型文件的方法。

    1/2/2009

    Creating Workflows in Plone(译)

    此文译自Plone文档《Creating Workflow in Plone》,原文链接:

    What is Workflow?

    什么是工作流

    Workflow is the series of interactions that should happen to complete a task. Business organizations have many kinds of workflow. For example, insurance companies process claims, delivery companies track shipments, and schools accept applications for admission. All these tasks involve several people, sometimes take a long time, and vary significantly from organization to organization.

    工作流是一系列交互行为,它们共同作用以完成一项任务。商业机构有许多种工作流。例如,保险公司处理索赔,快递公司跟踪货物,和学校接受入学申请等。所有这类任务都会涉及某些参与者,有的时候会持续很长时间,并且不同的组织或者机构之间会不尽相同。

    The goal of workflow software is to streamline and track workflow activity. Since different organizations have different workflow processes, workflow software must be flexible and easy to customize.

    工作流软件的目标是简化流程(to streamline)和跟踪工作流活动。由于不同的组织有不同的工作流处理过程,因此工作流软件必须是灵活的和易于自定义的。

    The DCWorkflow Concept

    DCWorkflow概念

    DCWorkflow makes a few simple assumptions about your workflow:

    DCWorkflow对你的工作流做了一些简单的假设:

    • There is a single object in the system that represents the task to be completed.

    系统中只有一个单独的对象表示要完成的任务。

    • Every object of a given type goes through the same workflow.

    每一个给定类型的对象在同一个工作流里面流动

    • Tasks are assigned to user roles, not individuals.

    任务被分配个用户角色,而不是个人

    DCWorkflow makes it easy to implement workflows that fit this description. If your workflow does not fit these criteria, you should weigh the alternatives. One alternative is AlphaFlow, a more powerful and complex workflow engine for Plone.

    DCWorkflow使得实现满足上述假设的工作流变得容易。如果你的工作流不符合这些条件,那么你应该考虑其它的替代产品。AlphaFlow是另外一个选择,为Plone而生的更加强大和复杂的工作流引擎。

    Workflows for complex use cases can become very unwieldly to build and maintain via the ZMI-based method this tutorial demonstrates. If you are building non-trivial workflows, we recommend you strongly consider using ArchGenXML and a UML modeling tool that will help you make sure your workflows are complete and correct. See the ArchGenXML tutorial, especially the section on workflows, for a great introduction.

    对于复杂用例,这篇指南所关注的通过ZMI创建和维护工作流的方法就会显得力不从心了。如果你正在构建产品级别的工作流,我们强烈建议你考虑使用ArchGenXML和UML建模工具,它们会帮助你完整地、正确地完成你的工作流。请参见ArchGenXML指南,它提供了非常棒的介绍,特别是涉及工作流的部分

    Defining Workflow States

    定义工作流状态

    Using workflow states you can add state to your content that is specific to your business process.

    使用工作流状态,能够给你的内容对象添加特定于你的商业流程(business process)的状态信息。

    CMF comes with a default workflow with three states: private, pending, and published. In the default configuration, all content in the CMF is set to operate in that workflow. When an object is in the private state, only the user who created it and site managers can view and change it. The user is provided with a link to "submit" the content, which puts it in the pending state. Then a user with the "reviewer" role is given the opportunity to either publish or reject the submission, which moves the content object to either the published or private state.

    CMF带有一个默认的工作流,它有三种状态:私有(private),待审(pending),和已发布(published)。在默认配置里,CMF中的所有内容对象都被设置为在这个工作流中活动。当一个对象处于私有(private)状态的时候,只有创建它的用户和站点管理员才能查看和修改。系统会为这样的用户提供一个链接用来提交(submit)内容,使其进入待审(pending)状态。接下来,具有审核人(reviewer)角色的用户就有机会发布或者驳回提交,即更改内容对象的状态到已发布或者私有。

    图示1:简单的状态机图例

    Your business process will most likely require a different set of states. For example, a workflow could naturally model the process of ratifying a bill in a state legislature. You could start by creating a Private state to be used while the author is creating a new bill, a Public state used before voting, a Voting state during which time legislators are allowed to cast their votes, a Final Review state which gives the executive branch time to review it, a Vetoed state, and a Passed state. (See Illustration 1.)

    你的商业流程在多数情况下可能需要一组不同的状态。例如,可以用工作流很自然的为州议会的议案批准流程建模。从创建私有(private)状态开始,在创建一个新议案的时候使用,投票前使用公开(Public)状态,在议员投票期间使用正在投票(Voting)状态,最终审核(Final Review)状态给州长审核议案的时间,这会产生否决(Vetoed)和已通过(Passed)两个状态。(参见图例1)

    图示2:使用泳道设计工作流

    One good way to determine what states you need in your business process is to first draw a diagram with "swim lanes". (See Illustration 2.) Draw a diagram with each relevant user role at the head of a column, then draw dotted lines between the columns. In the legislature example, the roles might be Owner, Public, Senator, and President. Draw a state diagram that shows the flow of your content (in the example, a bill) between the different users. Then create a workflow state for each bubble you draw in your diagram. (See Illustrations 3 and 4.)

    决定在你的商业流程中使用何种状态的最好的办法是先还一张带有泳道(swim lanes)的图示。(参见图例2)画一张图示,在每一列的顶部放置相关的用户角色,然后在列之间画上点划线。在议会的例子中,角色可能会有所有者(Owner)、公众(Public)、参议员(Senator)和州长(president)。画一个状态图,它展示你的内容(在例子中是议案)在不同用户之间的流动。接着为每一个画在图示中的气泡创建一个工作流状态。(见图例3和4)

    A technical note: changing the workflow state of an object does not move it to a different location or add Python attributes to the object. Instead, it asks the workflow tool to set the workflow state of the object and the workflow tool can choose how the state will be stored. The default implementation of the workflow tool stores the workflow state in the workflow_history attribute of CMF content objects.

    技术注释:更改一个对象的工作流状态,不会把该对象移动到其他地方或者给它添加Python属性。相反,它会要求工作流工具(workflow tool)设置对象的工作流状态,工作流工具自己选择如何存储状态信息。默认的工作流工具的实现使用CMF内容对象的workflow_history属性存储工作流状态。

    图示3:单击portal_workflow工具中的“Add Workflow”按钮添加工作流

    图示4:添加状态

    Defining Workflow Transitions

    定义工作流变换(Workflow Transition)

    Transitions are the arrows in a state diagram. Generally, for every arrow you draw in your state diagram, create a transition. Some state diagrams, however, have a lot of arrows pointing to a single state. In that case it might be better to create just one transition that you can reuse in modeling most of the transitions that lead to that state.

    状态图示中的箭头即是变换。一般的,每当你在状态图示中画一个箭头,就创建了一个变换。然而,某些状态图示有许多箭头指向一个单独的状态。在这种情况下,更好的办法也许是只创建一个变换,你能够在建模大多数通向那个状态的变换中重用它。

    Each transition requires a destination state. Select the destination state from the drop-down box. (See Illustration 5 below.)

    每一个变换需要一个目标状态。从下拉列表框中选择目标状态。(参见图示5)

    图示5:配置变换

    Transitions are usually protected by a guard condition. If you drew swimming lanes as suggested in Illustration 2, notice that many of the arrows cross the swimming lanes. Every time you cross a swimming lane you need a guard condition. A guard condition can be a permission, a role, or a workflow expression (described later). Guard conditions ensure that only users with the required permission, role, or other criteria can move the object to the new state.

    变换通常受到保证条件(guard condition)的保护。如果你像图示2建议的那样画了泳道,那么你会注意到许多箭头穿越了泳道。每次穿越泳道,都需要一个保证条件。保证条件可以是许可,角色,或者工作流表达式(稍后介绍)。保证条件确保拥有所需权限、角色或者其他条件的用户才能把对象移动到新的状态。

    Most transitions are initiated by a user action. For each transition initiated by a user action, enter the information for the corresponding link that should be displayed to the user in the actions box. The link will only be displayed when the user would be allowed to perform the transition.

    大多数变换是由用户操作引起了。针对每一个由用户引发的变换,为相应的链接输入信息,它应该在操作框(action box)中显示给用户。仅当允许用户执行变换时,才会显示链接。

    Sometimes you need special states and transitions in your workflow diagram that model actions performed in the background, not by any user. In that case you might need to set up transitions that are initiated automatically. Zope will proceed through automatic transitions whenever the guard condition allows it.

    有的时候,你会用一张工作流图示建模那些在后台执行,并且不需要用户干预的操作,同时在图中需要有一些专门的状态和变换。这样你可能需要设置被自动引发的变换。无论保证条件是否允许,Zope都会执行所有自动变换。

    Once you have defined all the transitions, go back to your workflow states and define which transitions are allowed to leave those states.

    一旦定义了所有的变换,回到你的工作流状态,接着定义允许哪些变换离开这些状态。

    Defining Variables

    定义变量

    Often a simple flow of states can't model all the details of a business process. For example, in the bill-passing example, a bill might be allowed to be revised and resubmitted once it is vetoed, but only if it has been vetoed once. If it is vetoed a second time, it is killed for good. To model this behavior, the state machine needs to carry a bit of extra information that "remembers" the past veto.

    简单的状态流不能建模所有的商业流程细节。例如,在上述的审核议案的例子中,可能允许审阅一个议案,同时当它被否决之后允许被再次提交,但是仅限一次。如果议案被否决两次,最好将它彻底废除。为这种行为建模,状态机需要留意额外的、记录了过去否决的信息

    A variable is a piece of information that transcends states. Most variables are persistent. A variable might hold a counter, a flag, the name of the last user who did some action, or any other simple object.

    相对状态而言,变量能够承载更多的信息。大多数变量是可持久的。一个变量可以容纳计数器,标志,上一个执行了某个操作的用户名称,或者任何其他的简单对象。

    图示6:默认的Plone工作流中的标准工作流变量

    Variables also serve the purpose of exposing metadata to the catalog or the user. There are five variables in the CMF default workflow: actor, action, comments, time, and review_history. The first four are there to keep a record of who executed the last transition, what they did, why, and when. The last variable makes it possible for the user to view the workflow history of an object. (See Illustration 6.)

    变量还达到了向目录(catalog)和用户暴露元数据(metadata)的目的。CMF默认的工作流有五个变量:actor,action,comments,time和review_history。前面的四个记录了谁执行了最后的那个变换,他们做了什么,为什么,以及什么时候做的。最后一个变量使用户能够查看对象的工作流历史(workflow history)。(参见图示6)

    Defining Worklists

    定义工作列表(Worklists)

    Some users need notification of work that needs to be completed. For example, in the CMF default workflow, users with the Reviewer role need to be told when there are items pending review, so they can visit them and either publish or reject them.

    某些用户需要在工作完成之后得到通知。例如,在CMF的默认工作流中,当有待审核项目的时候,得通知拥有审核人角色的用户,他们能够访问这些项目,并发布或者驳回它们。

    One way to accomplish this is with worklists. Worklists add links to users' actions box when there are items in a certain state. The CMF default workflow supplies one worklist. It shows the Pending Review link to reviewers when there are items they are allowed to review.

    达到上述目的的一个方法就是使用工作列表(Worklist)。当具有特定状态的项目出现的时候,工作列表即在用户的操作框(user's actions box)中添加链接。CMF的默认工作流提供了一个工作列表。当有允许审核人审核的项目出现的时候,就会给他们显示待审核(Pending Review)链接。

    After creating a worklist, enter the name of the state it matches. Use a guard condition to make only certain users see it. Also enter the name and URL of the link to be displayed.

    在创建工作列表之后,输入它匹配的状态的名称。使用保证条件(guard condition)只让某些用户能够看到。同时还要输入显示那些项目的URL链接的名称。

    Defining Scripts

    定义脚本

    You may need to perform actions like sending an email or invoking another workflow when users execute specific transitions. You can do this by writing scripts. Scripts can be any Zope object, but Scripts (Python) are most likely the best choice.

    当用户执行特定的变换的时候,你可能需要执行一些操作,比如发送一封电子邮件,或者触发另外一个工作流。你可以撰写脚本完成这些任务。脚本可以使任何Zope对象,但是Python脚本对象通常是最好的选择。

    Scripts are passed one parameter, the state_change object of a workflow expression. Remember that your script is executed with the permissions of the user who invokes the transition, rather than your own permissions, unless you give the script proxy roles.

    工作流表达式(Workflow expression)的state_change对象被当作一个参数传入脚本。记住,脚本是在触发变换的用户的权限下执行的,而不是你自己的权限,除非给脚本设置代理角色(proxy roles)。

    Once a script is in the Scripts container of a workflow you can visit a transition and select the script to be executed. The script will be executed before the state change and before variables are updated. It can raise exceptions to veto the action or an ObjectMoved or ObjectDeleted exception to tell the workflow that the object has moved or has been deleted.

    一旦脚本处于工作流的脚本容器中,你就可以访问变换,并且选择想要执行的脚本。脚本在改变状态之前和更新变量之前被执行。它可以抛出各种异常以拒绝操作,或者抛出ObjectMoved或ObjectDeleted异常告诉工作流,对象已经被移动或者被删除。

    Defining Permissions

    定义权限

    In a business process, the workflow state of an object usually affects who is allowed to perform non-workflow actions on the object. For example, in the CMF default workflow, the owner of a piece of content is allowed to edit it when it is in the private state, but not when it is in the published state. Anonymous users are allowed to see a piece of content only if it is in the published state.

    在商业流程中,对象的工作流状态经常影响着谁被允许在对象上执行非工作流操作。例如,在CMF的默认工作流,当内容处于私有状态的时候,允许内容的所有者编辑该对象,但是当内容处于已发布状态的时候,则是不允许的。只有当内容处于已发布状态时,才允许匿名用户看到。

    CMF accomplishes this by updating the role to permission mappings for objects based on their workflow state. To do this in your own workflow, first determine which permissions should be managed by your workflow by selecting them using the workflow Permissions tab.

    CMF的实现方法是:基于对象的工作流状态,为对象更新角色到权限的映射关系。在你的工作流中使用这个方法,首先要确定工作流应该管理哪些权限,使用工作流Permissions页选择它们。

    图示7:修改状态的权限影射关系

    Then visit the Permissions tab of each state and select which roles should have which permissions. This screen is very similar to the familiar Security tab. (See Illustration 7.) Remember to turn off the Acquire Permission checkbox as necessary.

    然后,访问每一个状态的Permissions页,选择哪些角色拥有哪些权限。这个屏幕中的内容与熟悉的Security页非常相似。(参见图示7)记住,必要时关闭获取(acquire Permission)权限。

    The role to permission mappings are stored on the objects themselves because that is where Zope has always stored them. Unfortunately this means that when you change the role to permission mappings in the workflow you need to make sure the changes are applied to the content objects throughout the system. But there is an easy workaround: the default portal_workflow tool has a button you can click to update the role to permission mappings in all content objects.

    角色到权限的映射关系存储在对象中,因为那正是Zope总是存储它们的地方。不幸的是,这意味着当你在工作流中修改了角色到权限的映射关系后,需要确保在整个系统中,其修改应用到了所有内容对象。有一个简单的方法:默认的portal_workflow工具有一个按钮,点击这个按钮能够更新所有内容对象的角色到权限的映射关系。

    Workflow Expressions

    工作流表达式

    A workflow expression is a TALES expression. TALES expressions are fully described at:

    工作流表达式即TALES表达式。下面的链接完整的描述了TALES表达式。

    Some of the contexts have slightly different meanings from what is provided for expressions in page templates.

    从为表达式提供的内容看,在页面模板中,一些上下文对象的含义略微有所不同。

    • here: The content object.

    here:内容对象

    • container: The content object's container

    container:包含内容对象的容器

    Several other contexts are also provided.

    其它几个上下文对象:

    • state_change: A special object containing info about the state change

    state_change:一个专门的对象,包含了有关状态改变的信息

    • transition: The transition object being executed

    transition:正在执行的变换对象

    • status: The former status

    status:前一个状态

    • workflow: The workflow definition object

    workflow:工作流定义对象

    • scripts: The scripts in the workflow definition object

    scripts:工作流定义对象(workflow definition object)的脚本

    state_change objects provide the following attributes:

    state_change对象提供了如下属性:

    • status is a mapping containing the workflow status.

    status:包含了工作流状态的映射。

    • object is the object being modified by workflow.

    object:正在被工作流修改的对象

    • workflow is the workflow definition object.

    workflow:工作流定义对象

    • transition is the transition object being executed.

    transition:正在执行的变换对象

    • old_state is the former state object.

    old_state:前一个状态对象

    • new_state is the destination state object.

    new_state:目标状态对象

    • kwargs is the keyword arguments passed to the doActionFor() method.

    kwargs:传递到doActionFor()方法的关键字参数

    • getHistory(), a method that returns a copy of the object's workflow history.

    getHistory():一个方法,返回对象的工作流历史(workflow history)的拷贝

    • getPortal(), which returns the root of the portal.

    getPortal():返回portal的根

    • ObjectDeleted and ObjectMoved, exceptions that can be raised by scripts to indicate to the workflow that an object has been moved or deleted.

    ObjectDeleted和ObjectMoved:可以被脚本抛出的异常,给工作流指出某个对象已经被移动或者被删除

    • getDateTime() is a method that returns the DateTime of the transition.

    getDateTime():一个方法,返回变换的DateTime属性


    12/17/2008

    有助于学习Zope和Plone的资料哪里找

    plone.org官方中的所有加星的文档

    列举一部分:
    • Add-on Products Developer Manual
      • 在开发Plone产品的时候,开发者因该知道和了解的方方面面。没有触及技术细节。
    • b-org: Creating content types the Plone 2.5 way
      • 同样介绍了Plone产品开发的方方面面。与上面不同的是,作者深入技术细节,介绍了很多重要的概念和Zope开发技术。对于刚刚结束Zope和Plone开发的初学者来说,需要重点阅读以下几个章节的内容:
      • 上面这些章节的内容涉及了Zope和Plone开发的核心技术,例如Interface,Adapter,View和Event等。看不懂的话,没关系。尽量理解,让它们在心里留下深刻的印象,等待后面逐个破解问号。在拨云见日那一刻,你会觉得很爽。书呆子
    • Understanding and Using GenericSetup in Plone
    • Archetypes Developer Manual
      • Archetype是开发Plone产品首选的框架。它提供了丰富的schema来描述内容对象,并且能够自动生成与Plone站点的样式一致的用户界面。在这篇文章中,作者以一个Plone产品实例的创建过程,详细地描述了在Archetype框架下开发的全过程。如果此时你对Zope产品开发有所了解的话,那么肯定意识到这不就是Zope产品开发吗,只不过Plone让我们的工作变得简单许多了。没错,的确如此,Plone就是Zope的一个超级产品实例。
      • 实际操练一下文章的代码很有用。
    • Customization for developers

    Zope 2文档

    • The Zope Book
    • The Zope Developer Guide
    • Zope Page Templates Reference

    Zope 3文档

    其他

    Plone和Zope的安装包也带了大量很有用的学习资料。在安装完成之后,可以在Data\Products和zope\lib\python中找到。列举部分如下:

    • Zope CMF文档
      • 该文档存在于CMF的tar包的docs目录中。在学习Plone开发之前应该仔细阅读CMF中的所有文档。之后,再读Plone的文档,你会发现很多名词和概念都不是那么陌生。
    • Five
    • Viewlets and Viewlet Managers
    • Zope 3 Schemas
    • Zope 3 Forms

    8/21/2007

    调用页面模板对象(Page Template)

    在Zope中,可以像调用Python脚本对象和Z SQL方法一样,调用页面模板对象(Page Template)。重要的是在调用的时候,能够向页面模板对象传递必要的参数。调用代码的书写形式与调用一个对象的方法没什么两样,实际上就可以这样认为。下面用实例来说明如何调用。
    假设,在myapp文件夹中,有一个doSomething的Python脚本对象,用于应用逻辑的处理;另外有一个叫做showIt的页面模板,它用于显示doSomething的处理结果。doSomething脚本从REQUEST对象中检索查询参数,并且使用这些参数调用一个ZSQL方法,在成功返回查询结果后调用showIt模板显示结果集中的每一条记录。好了,我们分两步进行,首先看看doSomething脚本:
    ## Script (Python) "demo_script"
    ##bind container=container
    ##bind context=context
    ##bind namespace=
    ##bind script=script
    ##bind subpath=traverse_subpath
    ##parameters=
    ##title=
    ##
    req = context.REQUEST
    keyword = req["keyword"]
    rs = container.query(keyword=keyword)
    container.showIt(source=rs)
     
    接下来完成showIt页面模板的内容,在这里只显示数据展示的部分,忽略其余部分:
    <tal:block tal:define="rs options/source" tal:omit-tag="">
      <ul>
        <tal:block tal:repeat="item rs" tal:omit-tag="">
          <li tal:content="item/title">Some object's title</li>
        </tal:block>
      <ul>
    </tal:block>
     
    至此已经完成了全部代码的编写。请留意页面模板的第一行代码,正是options这个页面模板对象的内置变量,能够让我们查询调用传递进来的任何参数。
    Zope在内部框架中提供了调用页面模板的机制,这能使我们隐藏Web应用程序内部的处理逻辑,避免在URL中附加查询参数,达到向页面传递参数的目的;同时,这样的调用也能够让我们的Web的应用程序有更自然的面向对象的逻辑。
    7/5/2007

    克服TAL的限制,动态添加特殊HTML属性

    背景

    特殊的HTML属性并非对某些HTML属性的正式称谓。我们知道,属性是由名称和取值组成,然而HTML的某些元素却包含没有取值的属性,例如OPTION元素包含的selected属性,以及INPUT元素的disabled属性。特殊的HTML属性即指这些。

    在Zope Page Template中依据某些变量的取值,在呈现给站点浏览者的页面中动态地添加这些属性有些问题。原因有二:

    1. tal:attributes用于替换表达式中指定的属性值,这一点对特殊的HTML属性无济于事;即便在tal:attributes的表达式中能够使用Python表达式,但是出于安全方面的考虑,if关键字被限制不能使用;
    2. tal:condition没有逻辑上的else分支。

    解决办法

    既然TAL行不通,那么用Python Script来处理。解决办法是,创建一个用于生成包含特殊属性的完整HTML元素的脚本对象。以OPTION元素为例说明。

    需求:显示一个产品类别下拉框,并且根据已知的产品类别ID,将对应的列表项选中。

    实现

    Python脚本对象:

    ## Script (Python) generateOptionElement
    ##bind container=container
    ##bind context=context
    ##bind namespace=
    ##bind script=script
    ##bind subpath=traverse_subpath
    ##parameters=value, text, selected
    ##title=
    ##
    if selected:
       return '<option value="%s" selected>%s</option>' % (value, text)
    else:
       return '<option value="%s">%s</option>' % (value, text)

    脚本对象接受三个参数,参数value和text的意图从代码可以看出,参数selected则表明是否标示selected属性。

    TAL:

    <select name="categories">
     <tal:block tal:repeat="item context/getCategories" tal:omit-tag="">
       <tal:block
         tal:replace="structure
           python:context.generateOptionElement(
             item.categoryid, item.categoryname, item.categoryid=known_category_id)">
         Place holder</tal:block>
     </tal:block>
    </select>

    在这段TAL代码中,known_category_id是假设的已知的产品类型ID;另外一个需要注意的是tal:replace中的structure,这是必需的,因为generateOptionElement脚本对象返回一个包含HTML代码的字符串。

    7/4/2007

    在Zope中添加到PostGreSQL的数据库连接 for Windows

    在Zope中使用PostGreSQL数据库,需要安装ZPsycopgDA数据库适配器,它包含在psycopg2的源代码包中,psycopg2时针对PostGreSQL数据库产品的DB-API 2.0实现。安装ZPsycopgDA,并使其正常工作我们必须下载psycopg2的源代码包及其为Windows创建的二进制安装包。

    在哪里获得

    psycopg2源代码包和二进制安装包均可以在initd.org网站中找到。如initd.org的建议,psycopg2应该是我们目前的选择。它们的下载地址如下:
    有两点需要说明:
    1. psycopg2的最新版本是2.0.6,不过这个版本尚存在bug,因此上面的链接是2.0.5版本的;
    2. psycopg2有用于Python 2.5的安装包,视你的Zope版本确定下载哪个Python版本的安装包。

    如何使用

    • 解压缩psycopg2的源码压缩包。把其中的ZPsycopgDA文件夹拷贝到Zope安装实例的Products文件夹中;
    • 执行psycopg2二进制安装包。在Python安装实例的lib\site-packages中找到psycopg2文件夹,将其拷贝到Zope安装实例的lib\python文件夹中。注意,不是随Zope自带的Python的lib\site-packages文件夹;
    • 重新启动Zope服务。
    在重新启动Zope服务后,如果安装无误的话,进入Zope管理界面(ZMI)在Control_Panel\Products中能够找到“ZPsycopgDA (Installed product ZPsycopgDA)”这一项。此后你就可以添加Z Psycopg 2数据库连接对象了。