Dexterity开发手册:第四章 Schema驱动内容类型
Dexterity开发手册:第四章 Schema驱动内容类型
http://www.315ok.org/blogfolder/399
http://www.315ok.org/logo.png
Dexterity开发手册:第四章 Schema驱动内容类型
Dexterity开发手册:第四章 Schema驱动内容类型
[align=left][font=宋体]创建一个基于[/font]schema[font=宋体]的极小类型[/font][/align][align=left]4.1 [font=宋体]关于[/font]schema[/align][align=left]4.2 [font=宋体]关于[/font]FTI[/align][align=left]4.3 [font=宋体]测试这个类型[/font][/align]
[align=left]4.1关于schema[/align][align=left][font=宋体]为这个类型编写一个[/font]schema[/align]
[align=left][font=宋体]一个简单的[/font]Dexterity[font=宋体]类型包含一个[/font]schema[font=宋体]和一个[/font]FTI[font=宋体]([/font]Factory Type Information,[font=宋体]这个对象在[/font]ZMI[font=宋体]的[/font]portal_types[font=宋体]中配置),我们将在此创建一个[/font]schemata[font=宋体],同时将在下一节创建[/font]FTI[font=宋体]。[/font][/align][align=left][font=宋体]每一个[/font]schema[font=宋体]通常是在一个独立的模块里。因此,我们将添加三个文件到我们的产品:[/font]presenter.py,program.py,[font=宋体]和[/font]session.py[font=宋体]。每一个都将以一个[/font]schema[font=宋体]接口开始。[/font][/align][font=宋体]
首先,我们将定义一个信息工厂来帮助未来国际化的软件包。呈现在用户面前的每一个字符都应该包裹在[/font]_()[font=宋体]里面就像如下图所示的标题和描述。[/font][font=宋体]这个信息工厂存在于包的根文件[/font]_init_.py[font=宋体]里面。[/font]
[align=left][font=宋体]对于[/font]Presenter[font=宋体]类型,[/font]presenter.py[font=宋体]看起来像这样的:[/font][/align]
[align=left][font=宋体]对于[/font]Program[font=宋体]类型,[/font]program.py[font=宋体]看起来这样的:[/font][/align]
[align=left]Schema [font=宋体]接口与其他接口对比[/font][/align][align=left][font=宋体]你也许已经注意到,每个[/font]schema[font=宋体]本质上就是一个带有一些字段的接口([/font]zope.interface.interface[font=宋体])。这些标准字段都可以在[/font]zope.schema.package[font=宋体]里面找到。你应该从它的接口([/font]parts/omelette/zope/schema/interfaces.py[font=宋体])来有效的学习各种各样的[/font]schema[font=宋体]字段,同时回顾这个包的一些网上文档。当你需要一个文件字段时,可以查阅[/font]plone.namefile[font=宋体],当你需要使用引用时,你可以查阅[/font]z3c.relationfield[font=宋体],当你需要一个支持富文本模式的[/font]WYSIWYG[font=宋体]编辑器是,可以查找[/font]plone.app.textfield[font=宋体]。我们稍后会在该手册中覆盖这些字段类型。它们也可以在最后的参考中找到。[/font][/align][font=宋体]
和标准的借口不一样,然而,我们源于[/font]form.Schema[font=宋体](事实上的是[/font]plone.directives.form.Schema[font=宋体])。这仅仅是一个允许我们去添加一些形式提示到接口的标记接口,然后被[/font]Dexterity[font=宋体](事实上是[/font]the plone.autoform package[font=宋体])用来构建形式。查看[/font]plone.directives.form[font=宋体]文件可以来学习更多的关于各种提示。最常用的是[/font]form.fieldset()[font=宋体],来定义大量的字段,[/font]form.widget()[font=宋体],用来为一个特殊的字段设置一个部件,和[/font]form.omit()[font=宋体]用来从形式上隐藏一个或多个字段。我们稍后将会看到一些这方面的例子在这个手册里。[/font]
[align=left]4.2关于FTI[/align][align=left] [font=宋体]为该类型添加一个工厂类型信息对象。[/font][/align][align=left][font=宋体]有了合适的[/font]Schema[font=宋体],我们仅仅需要让我们的类型是可安装的。我们使用[/font]GenericSetup[font=宋体]来做这个。[/font][/align][align=left][font=宋体]首先,我们添加一个[/font]types.xml[font=宋体]文件到[/font]profiles/default[font=宋体]:[/font][/align]
[align=left][font=宋体]对[/font]Presenter[font=宋体]类型,我们有[/font]example.conference.presenter.xml[font=宋体]:[/font][/align]
[align=left][font=宋体]重点是:[/font][/align]
[align=left]4.3 测试schema驱动类型[/align][align=left][font=宋体]怎么启动[/font]Plone[font=宋体]和测试这个类型,和一些故障解决技巧。[/font][/align][align=left][font=宋体]每个类型都有一个[/font]schema[font=宋体]和[/font]FTI[font=宋体],我们的[/font]GenericSetup[font=宋体]属性注册在[/font]configure.zcml[font=宋体]里面,我们应该能够测试我们的类型。保证你已经运行了一个[/font]buildout[font=宋体],然后像平常一样启动[/font]./bin/instance fg[font=宋体]。添加一个[/font]Plone[font=宋体]站点,然后到[/font]ZMI[font=宋体]中的[/font]portal_quickinstaller[font=宋体]。你应该在那看到你的包,同时应该可以安装它。[/font][/align][font=宋体]一旦安装完成后,你应该能够添加新的内容类型的对象。[/font][align=left][font=宋体]如果[/font]Zope[font=宋体]没有启动:[/font]
[/align]
[/align]
英文原版
<<< [size=3]Dexterity开发手册:第三章开发环境搭建[/size]
[align=right]Dexterity开发手册:第五章>>>
[/align]
[align=left]4.1关于schema[/align][align=left][font=宋体]为这个类型编写一个[/font]schema[/align]
[align=left][font=宋体]一个简单的[/font]Dexterity[font=宋体]类型包含一个[/font]schema[font=宋体]和一个[/font]FTI[font=宋体]([/font]Factory Type Information,[font=宋体]这个对象在[/font]ZMI[font=宋体]的[/font]portal_types[font=宋体]中配置),我们将在此创建一个[/font]schemata[font=宋体],同时将在下一节创建[/font]FTI[font=宋体]。[/font][/align][align=left][font=宋体]每一个[/font]schema[font=宋体]通常是在一个独立的模块里。因此,我们将添加三个文件到我们的产品:[/font]presenter.py,program.py,[font=宋体]和[/font]session.py[font=宋体]。每一个都将以一个[/font]schema[font=宋体]接口开始。[/font][/align][font=宋体]
首先,我们将定义一个信息工厂来帮助未来国际化的软件包。呈现在用户面前的每一个字符都应该包裹在[/font]_()[font=宋体]里面就像如下图所示的标题和描述。[/font][font=宋体]这个信息工厂存在于包的根文件[/font]_init_.py[font=宋体]里面。[/font]
from zope.i18nmessageid import MessageFactory
_ =MessageFactory("example.conference")[font=宋体]注意我们怎么使用包的名称作为翻译域。[/font][align=left][font=宋体]现在可以为我们的三种类型定义[/font]schemata。[/align][align=left][font=宋体]对于[/font]Presenter[font=宋体]类型,[/font]presenter.py[font=宋体]看起来像这样的:[/font][/align]
from five import grok
from zope import schema
from plone.directives import form, dexterity
from plone.app.textfield import RichText
from plone.namedfile.field import NamedImage
from example.conference import _
class IPresenter(form.Schema):
"""A conference presenter. Presenters can be added anywhere.
"""
title = schema.TextLine(
title=_(u"Name"),
)
description = schema.Text(
title=_(u"A short summary"),
)
bio = RichText(
title=_(u"Bio"),
required=False,
)
picture = NamedImage(
title=_(u"Picture"),
description=_(u"Please upload an image"),
required=False,
)[font=宋体]注意我们是如何为[/font]name[font=宋体]和[/font]summary[font=宋体]使用字段名的标题和描述的。我们这么做为[/font]Plone[font=宋体]的文件夹清单和检索中使用的默认的标题和描述数据元提供值。一般情况下,每一个类型都应该有一个标题字段,尽管它可以被行为(后面将会讲述)来规定。[/font][align=left][font=宋体]对于[/font]Program[font=宋体]类型,[/font]program.py[font=宋体]看起来这样的:[/font][/align]
from five import grok
from zope import schema
from plone.directives import form, dexterity
from plone.app.textfield import RichText
from example.conference import _
class IProgram(form.Schema):
"""A conference program. Programs can contain Sessions.
"""
title = schema.TextLine(
title=_(u"Program name"),
)
description = schema.Text(
title=_(u"Program summary"),
)
start = schema.Datetime(
title=_(u"Start date"),
required=False,
)
end = schema.Datetime(
title=_(u"End date"),
required=False,
)
details = RichText(
title=_(u"Details"),
description=_(u"Details about the program"),
required=False,
)[align=left][font=宋体]最后,[/font]Session[font=宋体]类型的[/font]session.py[font=宋体]看起来这样的:[/font][/align]from five import grok
from zope import schema
from plone.directives import form,
dexterity
from plone.app.textfield import RichText
class ISession(form.Schema):
"""A conference session. Sessions are managed inside Programs.
"""
title = schema.TextLine(
title=_(u"Title"),
description=_(u"Session title"),
)
description = schema.Text(
title=_(u"Session summary"),
)
details = RichText(
title=_(u"Session details"),
required=False
)[font=宋体]注意我们还没有添加关于[/font]speakers or tracks[font=宋体]的信息。我们要覆盖词汇与参考在我们添加这些信息的时候。[/font][align=left]Schema [font=宋体]接口与其他接口对比[/font][/align][align=left][font=宋体]你也许已经注意到,每个[/font]schema[font=宋体]本质上就是一个带有一些字段的接口([/font]zope.interface.interface[font=宋体])。这些标准字段都可以在[/font]zope.schema.package[font=宋体]里面找到。你应该从它的接口([/font]parts/omelette/zope/schema/interfaces.py[font=宋体])来有效的学习各种各样的[/font]schema[font=宋体]字段,同时回顾这个包的一些网上文档。当你需要一个文件字段时,可以查阅[/font]plone.namefile[font=宋体],当你需要使用引用时,你可以查阅[/font]z3c.relationfield[font=宋体],当你需要一个支持富文本模式的[/font]WYSIWYG[font=宋体]编辑器是,可以查找[/font]plone.app.textfield[font=宋体]。我们稍后会在该手册中覆盖这些字段类型。它们也可以在最后的参考中找到。[/font][/align][font=宋体]
和标准的借口不一样,然而,我们源于[/font]form.Schema[font=宋体](事实上的是[/font]plone.directives.form.Schema[font=宋体])。这仅仅是一个允许我们去添加一些形式提示到接口的标记接口,然后被[/font]Dexterity[font=宋体](事实上是[/font]the plone.autoform package[font=宋体])用来构建形式。查看[/font]plone.directives.form[font=宋体]文件可以来学习更多的关于各种提示。最常用的是[/font]form.fieldset()[font=宋体],来定义大量的字段,[/font]form.widget()[font=宋体],用来为一个特殊的字段设置一个部件,和[/font]form.omit()[font=宋体]用来从形式上隐藏一个或多个字段。我们稍后将会看到一些这方面的例子在这个手册里。[/font]
[align=left]4.2关于FTI[/align][align=left] [font=宋体]为该类型添加一个工厂类型信息对象。[/font][/align][align=left][font=宋体]有了合适的[/font]Schema[font=宋体],我们仅仅需要让我们的类型是可安装的。我们使用[/font]GenericSetup[font=宋体]来做这个。[/font][/align][align=left][font=宋体]首先,我们添加一个[/font]types.xml[font=宋体]文件到[/font]profiles/default[font=宋体]:[/font][/align]
<object name="portal_types">
<object name="example.conference.presenter" meta_type="Dexterity FTI" />
<object name="example.conference.program" meta_type="Dexterity FTI"/>
<object name="example.conference.session" meta_type="Dexterity FTI"/>
</object>[align=left][font=宋体]我们使用包名作为前缀和小写的类型名称,以创建一个唯一的名称。重要的是[/font]meta_type[font=宋体]是一个[/font]Dexterity FTI[font=宋体]。[/font][/align][font=宋体]然后我们需要为每个类型添加一个[/font]XML[font=宋体]文件,文件名称和类型名称匹配。[/font][align=left][font=宋体]首先,我们添加一个目录[/font] profiles/default/types[font=宋体],然后添加下面的内容:[/font][/align][align=left][font=宋体]对[/font]Presenter[font=宋体]类型,我们有[/font]example.conference.presenter.xml[font=宋体]:[/font][/align]
<?xml version="1.0"?>
<object name="example.conference.presenter" meta_type="Dexterity FTI"
i18n:domain="example.conference"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<!-- Basic metadata -->
<property name="title" i18n:translate="">Presenter</property>
<property name="description" i18n:translate="">A person presenting sessions</property>
<property name="content_icon">user.gif</property>
<property name="allow_discussion">True</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types" />
<!-- schema interface -->
<property name="schema">example.conference.presenter.IPresenter</property>
<!-- class used for content items -->
<property name="klass">plone.dexterity.content.Item</property>
<!-- add permission -->
<property name="add_permission">cmf.AddPortalContent</property>
<!-- enabled behaviors -->
<property name="behaviors">
<element value="plone.app.content.interfaces.INameFromTitle" />
</property>
<!-- View information -->
<property name="default_view">view</property>
<property name="default_view_fallback">False</property>
<property name="view_methods">
<element value="view"/>
</property>
<!-- Method aliases -->
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<!-- Actions -->
<action title="View" action_id="view" category="object" condition_expr=""
url_expr="string:${object_url}" visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>[font=宋体]有相当数量的样板,这里实际上可以省略的,因为[/font]Dexterity FTI[font=宋体]默认会最注意这个方面的。然而,看到这些可供选择的方案是有用的,这样你知道你可以改变它。[/font][align=left][font=宋体]重点是:[/font][/align]
- 根元素的名称属性必须匹配types.xml和文件名称。
- 我们使用包的名称再次作为翻译名称,通过i18n:domain
- 我们为这个类型设置一个标题和描述
- 我们也指定一个图标。在此,我们使用一个来自Plone的plone_images皮肤的图标。稍后你将会学习更多的静态资源。
- 我们把global_allow设置为True。这意味着这个类型在标准文件夹里将是可添加的。
- Schema接口是被schema属性引用的。
- 我们设置Klass属性到标准的plone.dexterity.content.Item。也有plone.dexterity.content.Container。
- 我们指定添加权限的名称。默认的cmf.AddPortalContent应该被使用除非你配置一个定制的权限。定制的权限稍后会在手册中讲到。
- 我们添加一个行为。行为是可以重复使用的各个方面提供语义和(或)schema字段的。在这里我们添加INameFromTitle行为,将给我们内容对象一个基于这个Title属性的可读的标示符。稍后我们将会讲到其他的行为。
<?xml version="1.0"?>
<object name="example.conference.session" meta_type="Dexterity FTI"
i18n:domain="example.conference" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<!--Basic metadata -->
<property name="title" i18n:translate="">Session</property>
<property name="description" i18n:translate="">A session on the program</property>
<property name="content_icon">document_icon.gif</property>
<property name="allow_discussion">True</property>
<property name="global_allow">False</property>
<property
name="filter_content_types">True</property>
<property
name="allowed_content_types" />
<!-- schema interface -->
<property name="schema">example.conference.session.ISession</property>
<!-- class used for content items -->
<property name="klass">plone.dexterity.content.Item</property>
<!-- add permission -->
<property name="add_permission">cmf.AddPortalContent</property>
<!-- enabled behaviors -->
<property name="behaviors">
<element value="plone.app.content.interfaces.INameFromTitle" />
</property>
<!-- View information -->
<property name="default_view">view</property>
<property name="default_view_fallback">False</property>
<property name="view_methods">
<element value="view"/>
</property>
<!-- Method aliases -->
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<!-- Actions -->
<action title="View" action_id="view" category="object" condition_expr=""
url_expr="string:${object_url}" visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>[align=left][font=宋体]再次,这是一个项目。在此,我们已经设置[/font]global_allow[font=宋体]为[/font]False[font=宋体],因此这些对象应该仅仅在[/font]Program[font=宋体]里面才是可添加的。[/font][/align][align=left][font=宋体]在[/font]example.conference.program.xml[font=宋体]里面,[/font]Program[font=宋体]看起来像这样:[/font][/align]<?xml version="1.0"?>
<object name="example.conference.program" meta_type="Dexterity FTI"
i18n:domain="example.conference" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<!-- Basic metadata -->
<property name="title" i18n:translate="">Program</property>
<property name="description" i18n:translate="">A conference program</property>
<property name="content_icon">folder_icon.gif</property>
<property name="allow_discussion">True</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
<element value="example.conference.session" />
</property>
<!-- schema interface -->
<property name="schema">example.conference.program.IProgram</property>
<!-- class used for content items -->
<property name="klass">plone.dexterity.content.Container</property>
<!-- add permission -->
<property name="add_permission">cmf.AddPortalContent</property>
<!-- enabled behaviors -->
<property name="behaviors">
<element value="plone.app.content.interfaces.INameFromTitle" />
</property>
<!-- View information -->
<property name="default_view">view</property>
<property name="default_view_fallback">False</property>
<property name="view_methods">
<element value="view"/>
</property>
<!-- Method aliases -->
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<!-- Actions -->
<action title="View" action_id="view" category="object" condition_expr=""
url_expr="string:${object_url}" visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>[align=left][font=宋体]这个区别在这里是我们使用[/font]Container[font=宋体]类,而且我们过滤可包含的类型([/font]filter_content_types[font=宋体]和[/font]allowed_content_types[font=宋体])来允许仅仅[/font]Sessions[font=宋体]被添加到这个文件夹。[/font][/align][align=left]4.3 测试schema驱动类型[/align][align=left][font=宋体]怎么启动[/font]Plone[font=宋体]和测试这个类型,和一些故障解决技巧。[/font][/align][align=left][font=宋体]每个类型都有一个[/font]schema[font=宋体]和[/font]FTI[font=宋体],我们的[/font]GenericSetup[font=宋体]属性注册在[/font]configure.zcml[font=宋体]里面,我们应该能够测试我们的类型。保证你已经运行了一个[/font]buildout[font=宋体],然后像平常一样启动[/font]./bin/instance fg[font=宋体]。添加一个[/font]Plone[font=宋体]站点,然后到[/font]ZMI[font=宋体]中的[/font]portal_quickinstaller[font=宋体]。你应该在那看到你的包,同时应该可以安装它。[/font][/align][font=宋体]一旦安装完成后,你应该能够添加新的内容类型的对象。[/font][align=left][font=宋体]如果[/font]Zope[font=宋体]没有启动:[/font]
[/align]
- 查找控制台上的错误信息,同时保证你在前端运行着./bin/instance fg。你会有一个语法错误或者一个ZCML错误。
- 确保这些包是被mr.developer取出,或者你在buildout.cfg中有一个develop行作为一个扩展的egg来装载它。develop= src/*应该够了,但是你也可以很明确的添加包,例如使用develop = src/example.conference。
- 确保这个包确实是作为一个egg家在的。它应该在egg部分中的[instance]里面被引用。你可以通过查看生成的bin/instance script(bin\instance-script.py在windows中)检查这个包在buildout里面是否正确的配置了。在文件的顶部的eggs列表中应该有一行对应你的包的。
- 确保这个包的ZCML被装载了。你可以通过安装一个ZCML部件(通过buildout.cfg中的[instance]部分中的zcml选项)或者添加一个<include/>行在另外一个包的configure.zcml来装载ZCML。然而,这最简单的方法在Plone3.3及以上版本中是添加z3c.autoinclude.plugin接入点到setup.py中。
- 确保你已经添加一个<genericsetup:registerProfile/>部分到configure.zcml里面。
- 在Plone站点的根目录的error_log中查找错误,在你的控制台,或者在你的日志文件中。
- 检查属性文件的语法和位置。记住你需要一个types.xml列出你的类型,和相应的文件在types/*.xml。
[/align]
- 确保你的schema源于form.Schema。
- 记住这些指示需要你指定正确的字段名称,即使他们放置在相关字段的前面或者后面。
- 检查在Configure.zcml里面有一行<grok:grokpackage="." />。
英文原版
<<< [size=3]Dexterity开发手册:第三章开发环境搭建[/size]
[align=right]Dexterity开发手册:第五章>>>
[/align]