The content package and its modules¶
Description
Now we are ready for the core of the product, i.e. the content class definition module (content/message.py).
Since it provides a Python (sub)package, the ‘content’ directory contains 2 modules:
- the usual __init__ module that initializes the package,
- the message module (message.py) where we will define the ‘InstantMessage’ class.
The message module¶
First imports we need
We start the message module by adding the general
Zope-related imports we need, such as the
implements
function from the
zope.interface
module:
from zope.interface import implements
We need to use a few classes and/or functions provided by
the core of our codebase, i.e. CMF/Archetypes. It is
possible to have access to all the classes and helper
functions made publicly available by Archetypes, by
importing its façade or API module (Products.Archetypes.atapi
) this way:
from Products.Archetypes import atapi
i18n support
It is always a good idea to have an i18n-enabled application. To start using Zope’s i18n support, let’s import the MessageFactory object created in the product’s startup module:
from example.archetype import exampleMessageFactory as _
The MessageFactory referenced with the
_
symbol can now be used to provide i18nized labels,
descriptions, and all the miscellaneous text snippets that
are injected in the UI, also known as “messages”. For a
content type implementation, this is useful for UI
widgets; for example to define the label of the content
title field widget, we could define
label
=
_(u'Title')
. (See later for how we make use of this tool/practice.)
ATContentTypes-based schema definition
You can base your implementation directly on these stock
Archetypes schemas. But you can add better support for
Plone’s UI and content management policies (such as the
parameters that allow showing/hiding contents in the
navigation menu), by basing the implementation on
ATContentTypes’ base schema,
ATContentTypeSchema
. To be compatible with that schema, you will also need
to inherit from ATContentTypes’ ATCTContent base class.
Let’s add the import of modules we need for that:
from Products.ATContentTypes.content import base
from Products.ATContentTypes.content import schemata
Then, we import things internal to our product package,
such as our defined interface(s) and the configuration
module (for access to things such as
PROJECTNAME
and
MESSAGE_PRIORITIES
):
from example.archetype.interfaces import IInstantMessage
from example.archetype import config
Now, we have everything we need to start building the
schema, and then the class that will use it. We start out
by copying ATContentTypes’
ATContentTypeSchema
, and we extend it by adding our specific fields and/or
overriden field properties.
schema = schemata.ATContentTypeSchema.copy() + atapi.Schema((
atapi.StringField('priority',
vocabulary = config.MESSAGE_PRIORITIES,
default = 'normal',
widget = atapi.SelectionWidget(label = _(u'Priority')),
),
atapi.TextField('body',
searchable = 1,
required = 1,
allowable_content_types = ('text/plain',
'text/structured',
'text/html',),
default_output_type = 'text/x-html-safe',
widget = atapi.RichWidget(label = _(u'Message body')),
),
))
Notes:
- To instantiate an Archetypes schema object, you pass a tuple of field objects to the ‘Schema’ class.
We define the body of the InstantMessage object using a RichWidget, so the user can use formatting with a WYSIWYG editor.
The full list of out-of-the-box available Fields and Widgets can be found in the Fields section at the end of the manual. You can find more 3rd party fields and widgets here.
Content-type class definition
The last step is to create the class for the InstantMessage content. It inherits from ATContentTypes’ ATCTContent, which itself is based on AT’s BaseContent, which automatically gives its ‘id’ and ‘title’ attributes, and the entire Dublin Core metadata set (Title, Description, Creator, CreationDate, etc):
class InstantMessage(base.ATCTContent):
"""An Archetype for an InstantMessage application"""
implements(IInstantMessage)
schema = schema
The first information we add for the class definition is
saying that it implements the
IInstantMessage
interface that we have previously defined (in
interfaces.py
) and imported.
implements(IInstantMessage)
The next thing is assigning the reference of the
Archetypes schema, using the
schema
class attribute.
schema = schema
The content class definition is done. Now, we are ready to
activate the content type in Archetypes’ internal types
registry. This is done using the helper function called
registerType
.
atapi.registerType(InstantMessage, config.PROJECTNAME)
Congratulations! You have just created your first Archetype for Plone! It allows you to handle the content of an instant message with Zope-based persistent objects which:
- can be added within your Plone site,
- published by the Zope Publisher, which means you can visit them via their URLs, etc…
- searched since they are automatically indexed,
- etc…
But wait! You have some final packaging work to do to ease installation of the product within your Plone site.
Notes:
- At the content class level, you could also provide the ‘actions’ attribute useful for defining the settings of the type’s actions (for the portal_actions tool). In Plone 3, this is no more needed, since this is part of the FTI’s configuration details, and should be provided using GenericSetup, in the types-related XML files (i.e. ‘profiles/default/types/InstantMessage.xml’). Same for the aliases.
The __init__ module¶
The trick here is to simply import the message module so that all the code of that module gets interpreted as soon as the Python interpreter initializes the package.
import message