锻造坊 - CMF 类型
在过去的几个月中,我们已经讨论了内容管理系统 (CMS) 的一般概念,以及 Zope 的内容管理框架 (CMF)。Zope 的 CMF 旨在为开发人员提供创建自己的内容管理系统所需的工具。当然,任何使用过 CMS 的人都知道,即使是最专有的 CMS,在使用前也需要进行大量的修改、返工和定制。因此,Zope 不仅降低了基础软件的价格,还提供了一个丰富的环境,使得开发和定制 CMS 相对容易。
当您创建一个 CMF 站点时,您(作为站点管理员)可以添加、修改和删除文档。点击文件夹内容链接,点击“新建...”按钮,指示您要添加的文档类型及其 ID,然后点击“添加”按钮。输入元数据(即标题、描述、主题和内容类型),点击“更改并编辑”按钮,添加一些内容,您就可以开始运行了。
然而,虽然现有的内容类型对于简单的站点来说已经足够了,但更复杂的站点会希望创建自己的自定义类型。CMF 提供了几种方法来做到这一点。本月,我们将研究 CMF 中的类型——我们如何使用它们、定制它们的行为、安装新的类型,甚至创建新的类型来处理自定义内容。
创建新类型最简单的方法是使用 CMF 内置的基于 Web 的类型扩展系统。它允许您创建一个新的类型,默认情况下,该类型与其父类型共享方法、属性、操作、演示模板和图标。当您使用基于 Web 的扩展系统创建新类型时,您可以修改这些项中的任何一项,但方法和属性除外。换句话说,您创建的新类型可以具有与其父类型不同的外观,但它的行为方式仍然与父类型非常相似。
例如,让我们转到所谓的类型工具,通过点击 CMF 站点的管理界面中的 portal_types 可以访问该工具。如果您在 Zope 中还没有定义 CMF 站点,您可以通过从基于 Web 的 Zope 管理界面右上角的“添加...”菜单中选择“CMF 站点”来创建一个。一旦您创建了站点,从管理界面中点击其图标,就会显示许多不同的定制工具,每个工具都有一个看起来像扳手的图标。
当您首次进入类型工具时,您会看到当前定义的 CMF 类型列表,包括文件夹、文档、新闻条目、链接和主题。您可以通过点击您想要更改的类型的名称来检查和修改与这些类型关联的属性和操作。例如,如果您想检查或更改文件内容类型的工作方式,请点击“文件”。这将会在页面顶部弹出一组新的管理选项卡,其中“属性”(默认)和“操作”是 Zope 其他部分不常见的选项卡。实际上,“属性”是一个标准的 Zope 选项卡,但 CMF 类型有许多不寻常的属性名称。
除了您期望看到的标准属性之外,每种类型还具有以下影响其行为的属性
图标:一个描述应为此类型项目显示的图标的字符串。
产品元类型:描述 Zope 产品元名称。元名称用于 Zope 管理界面中的“添加...”菜单中。这也是 CMF 中类似的“添加...”菜单中使用的名称。
产品名称:指示定义 CMF 类型的 Zope 产品。由于文件和新闻条目类型都是在默认 CMF 安装中定义的,因此它们被列为位于 CMFDefault 产品中。实际上,如果您查看 /lib/python/products/CMFDefault,它是 CMF 1.3 中 CMF-1.3/CMFDefault 的符号链接,您应该看到 File.py 和 NewsItem.py,这两个 Python 模块定义了内容类型。要查看属性的初始值是如何设置的,请查看任何已定义的 CMF 类型的任何模块中的 factory_type_information 变量。
产品工厂方法:描述 CMF 应调用以创建类型新实例的方法。
过滤内容类型和允许的内容类型:即使它们是单独的属性,它们也协同工作。虽然所有 CMF 类型都存在这两个属性,但它们仅与类似文件夹的对象相关,例如文件夹和主题。第一个“过滤内容类型”是一个布尔值,指示“允许的内容类型”是否处于活动状态。第二个“允许的内容类型”允许您指定当前类型中可以包含哪些类型。因此,如果您有兴趣创建一个仅包含新闻条目的文件夹,您可以通过点击“是”,然后指示可以包含哪些类型来实现。
创建新 CMF 类型的最简单方法是使用基于 Web 的 CMF 类型创建工具,将其基于现有类型。此方法不允许您修改与类型关联的字段或方法,但它允许您更改与类型操作关联的权限、该类型是否可以被讨论,甚至更改此数据类型的显示方式。
例如,转到 portal_types 工具,然后从右上角的“选择要添加的类型...”菜单中选择“基于工厂的类型信息”。系统会提示您输入两条信息,新类型的 ID 或名称以及应基于的现有类型。我们正在创建 ATFDocument,这意味着我们基于 CMF Default: Document。
一旦您创建了新类型,它就可以从所有类型列表中看到,包括类型工具和您在其中创建类型新实例的内容视图。实际上,任何在门户上具有管理权限的人现在都可以在选项菜单中看到您的新 ATFDocument 类型,他们可以从中选择要创建的新类型。
如果 ATFDocument 和 Document 是相同的,那么这样做有什么意义呢?嗯,它们并不完全相同;相反,它们共享方法和整体类定义。关于此类型的其他信息,例如属性、权限和皮肤,默认与 Document 相同,但可以使它们看起来截然不同。这意味着,如果您希望 Document 的实例以黑底白字显示,且不进行讨论,而 ATFDocument 以黄底栗色文字显示,且进行讨论,您可以使用此方法快速轻松地做到这一点。而且,如果您升级 CMF 副本,ATFDocument 将与 Document 一起自动更新。
当然,有时您会想要创建一个类型,该类型具有与现有类型显着不同的字段或行为。有几种方法可以做到这一点,但最灵活(并且具有挑战性且文档记录不完善)的方法是创建一个新的 Zope 产品,该产品符合 CMF 规则。例如,所有 Python 包都必须在包的根目录中包含一个 __init__.py 文件。此文件可以是空的,也可以包含在首次加载到内存中时评估的语句。对于产品,__init__.py 是首次通过使用 initialize() 方法将类注册到 Zope 的地方,该方法接受一个通常称为 context 的参数。因此,一个基本的 Zope 产品有一个 __init__.py,看起来像下面这个虚构的 MyProduct
import MyProduct def initialize(context): context.registerClass( MyProduct.MyProduct, constructors=(MyProduct.manage_addMyProductForm, MyProduct.manage_addMyProduct) )
当 Zope 启动时,它会遍历产品并使用适当的上下文调用 initialize() 方法。上下文是 Zope 获取系统的一部分,其中对象的属性由其在层次结构中的位置以及其类定义来定义。在上面的示例中,MyProduct 使用两个构造函数注册自身,即 manage_addMyProductForm 和 manage_addMyProduct 方法。
CMF 类型不仅必须向 Zope 注册自身,还必须向 CMF 注册自身,以便它可以出现在各种 CMF 工具中。因此,我们产品的 initialize() 方法需要包含特定于 CMF 的注册,这意味着 __init__.py 需要从 CMF 导入模块。此外,CMF 中的每种类型都必须使用 Products.CMFCore.utils 中的特定于 CMF 的初始化例程之一注册自身。例如,来自 CMFDefault 的 __init__.py(随 CMF 一起提供)首先定义它将注册的不同类
contentClasses = ( Document.Document , File.File , Image.Image , Link.Link , Favorite.Favorite , NewsItem.NewsItem , SkinnedFolder.SkinnedFolder )
然后,它为每个类定义构造函数
contentConstructors = \ ( Document.addDocument , File.addFile , Image.addImage , Link.addLink , Favorite.addFavorite , NewsItem.addNewsItem , SkinnedFolder.addSkinnedFolder )
当然,每种类型都可以有自己的特定工具
tools = ( DiscussionTool.DiscussionTool , MembershipTool.MembershipTool , RegistrationTool.RegistrationTool , PropertiesTool.PropertiesTool , URLTool.URLTool , MetadataTool.MetadataTool , SyndicationTool.SyndicationTool )
最后,包中的 initialize() 方法(此处略微缩写)使用 CMF 和 utils.ToolInit()(用于工具)或 ContentInit(用于内容)注册这些类。然后,它在接收到的内容上调用 initialize(context),从而将新对象注册到 Zope
def initialize( context ): utils.ToolInit('CMFDefault Tool', tools=tools, product_name='CMFDefault', icon='tool.gif', ).initialize( context ) utils.ContentInit( 'CMFDefault Content' , content_types=contentClasses , permission=AddPortalContent , extra_constructors=contentConstructors , fti=Portal.factory_type_information ).initialize( context ) context.registerClass(Portal.CMFSite, constructors=(Portal.manage_addCMFSiteForm, Portal.manage_addCMFSite, ))
正如您所看到的,上面版本的 initialize() 中的最后一条语句与示例 MyProduct() 中的 initialize() 版本中的最后一条语句类似,这表明 CMF 类型是 Zope 产品,只是包含了一些额外的钩子。
本文总结了我们对 Zope 作为内容管理平台的考察,该考察始于 Plone,并以 CMF 和 CMF 类型结束。现在我们已经更详细地了解了 CMF,让我们考虑一下对于需要 CMS 的项目,是否值得使用它。
好消息是 CMF 是一个强大而灵活的系统。在熟练且知识渊博的开发人员手中,CMF 可以以比市场上现有的专有系统更低的成本和更高的灵活性来生成自定义 CMS。一切都构建在 Zope 之上,Zope 专为快速开发而设计,这使得创建新类型、修改模板和开发功能变得快速而容易。
但 CMF,像许多开源软件一样,也遭受着缺乏最新和有用的文档的困扰。我确信 Plone CMS 成功的原因之一是 Plone 附带的优秀文档。
因此,如果您要使用 CMF,请准备好并愿意阅读大量的 Python 代码,进行大量的实验,并向其他 CMF 开发人员寻求帮助。鉴于 CMF 已经在 Zope 世界中扮演着核心角色,我预计 CMF 文档的数量和质量将继续提高。但在它提高之前,使用 CMF 将需要耐心、阅读源代码以及大量的试验和错误。
CMF 的当前状态是,除了最大和最复杂的内容管理系统之外,我对于将其用于任何其他用途都有些犹豫。也就是说,CMF 的灵活性和强大功能旨在解决这种规模的问题。简而言之,CMF 可能不适用于小型任务,但它可能非常适合大型任务。随着时间的推移,我预计 CMF 将在开源内容管理领域发挥越来越重要的作用,为快速开发自定义 CMS 软件提供框架。
Zope 的 CMF 是一个令人印象深刻的框架,用于构建自定义 CMS。我毫不怀疑 CMF 可以轻松创建 CMS,并且成本显着降低,工作量远小于完整的专有解决方案。也就是说,对于任何不熟悉 CMF 或不愿意花费大量时间学习它的人来说,CMF 仍然没有完全准备好投入实际应用。我认为 Plone 已将 CMF 推向聚光灯下,并且 Zope 3 将在很大程度上或完全与 CMF 合并,这意味着现在 Zope Corporation 更有动力使 CMF 比以前更令人印象深刻和文档更完善。
如果您有相当多的 Python 和 Zope 编程经验,您几乎肯定可以使用 CMF 将您自己的自定义类型创建为 Zope 产品——并使用这些类型,为您自己和您的客户创建令人印象深刻、有趣的站点。但是,在类型创建系统变得更容易理解之前,CMF 将不会获得 Zope 社区以外的关注。创建 Zope 产品不再是过去那种神秘的艺术,我预计在不久的将来,创建 CMF 类型也将受到类似的待遇。
下个月,我们将大幅改变方向,研究另一个名为 Bricolage 的开源 CMS。Bricolage 使用 Mason、mod_perl 和 PostgreSQL,在过去一年中取得了很大的进展,并且它在开源 CMS 社区中是一个越来越重要的参与者。
资源
Zope CMF 的主页是 cmf.zope.org。我不仅发现该站点难以导航,而且我无法轻松找到有关 CMF 的良好、有用的信息。
我发现的关于 CMF 类型的最佳介绍实际上不在 CMF 站点上,而是在 Plone 站点上,网址为 www.plone.org。例如,plone.org/documentation/CMFTypesBook/backtalk_book_view 上的文档是 CMF 类型手册,它既可读又包含示例。Plone 手册的第 8 章也包含一些关于 CMF 类型的良好信息,网址为 plone.org/documentation/book/8。
与往常一样,www.zopelabs.com 上的 ZopeLabs 提供了大量的示例代码和迷你教程,描述了如何在 CMF 中完成某些任务。
最后,如果您有兴趣为 CMF 创建新类型,请考虑 Archetypes,这是一个 SourceForge 项目,旨在使人们更容易创建新的 CMF 类型。实际上,CMF Collective 是一个 SourceForge 项目,其中包含许多您可能感兴趣的 CMF 类型。请务必查看 CVS 存储库,而不是依赖于 SourceForge 上提供的文件和类型。
Reuven M. Lerner (reuven@lerner.co.il) 是一位专门从事开源 Web/数据库技术的顾问。他和他的妻子 Shira 最近庆祝了他们的第二个女儿 Shikma Bruria 的出生。Reuven 的著作 Core Perl 于 2002 年初由 Prentice Hall 出版,第二本关于开源 Web 技术的书将于 2003 年由 Apress 出版。