Archetypes Developer Manual

« Return to page index

An in-depth manual about how to create new content-types in Plone using the Archetypes framework.

1. Introduction

What is Archetypes? A bit of history and future direction.

1.1. What is Archetypes?

Brief presentation of Archetypes.

Archetypes is a framework for developing new content types for a Plone project. Most content management projects involve introducing new types of content, which in the non-trivial case requires an informed understanding of how Zope and the CMF work. Archetypes provides a simple, extensible framework that can ease both the development and maintenance costs of CMF content types while reducing the learning curve for the simpler cases.

Compared to building content types using the stock CMF (through subclassing), Archetypes gives you the following advantages:

  1. automatically generates forms and views;
  2. provides a library of stock field types, form widgets, and field validators;
  3. allows defining custom fields, widgets, and validators;
  4. automates transformations of rich content;
  5. a built-in reference engine that gives the ability to link two objects together with a relation; such a "link" from a given object to another one is a Python object called a reference.

Since Plone 2.1, Archetypes has become the de-facto way of developing new content types, and a majority of third party products that are released these days use Archetypes.

1.2. Archetypes schemas

Introducing Archetypes-based schemas and fields.

Archetypes provides a robust framework for storing data attributes on content objects.  This framework consist of a number of Fields stored in a container called a Schema. Fields are simply specialized Python classes that allow you to store and retrieve data associated with an Archetypes object.

Fields provide a few functionalities. First, there are specialized field types for strings, lists of strings, integers, floating-point numbers, etc., that allow special handling of fields based on the type of data stored.

Some definitions

Before we go diving in, let's define some often-used terms:

  • Field: An Archetypes Field. This refers to an instance of a Field class defined in a Schema.
  • Schema: The "container" that Archetypes uses to store fields.
  • Schemata: A named grouping of fields. One Schema can have many schematas.
  • AT: Abbreviation for Archetypes.

Fields, Classes, and Objects

Archetypes Fields are Python objects contained within the Schema. A Field is defined once for an Archetypes content class. This single Field instance is used for every instance of that class.  Therefore, the relationship between Field instances and content classes is described as such: "A field instance belongs to exactly one class." A class, however, can have many different Field instances. Furthermore, every instance of an AT class uses the same set of Fields.  AT objects themselves do not contain unique Fields.

When Zope starts up, during product initialization, Archetypes reads the schema of the registered classes and "automagically" generates methods to read (the accessor) and change (the mutator) each of the fields defined.

Stock schemas

Archetypes includes three stock schemas:

  • BaseSchema: defines a normal content type,
  • BaseFolderSchema: defines a folderish content type (object can contain other objects),
  • BaseBTreeFolderSchema: for folders which need to handle hundreds or thousands of objects (even up to millions).

All three include two fields, id and title, as well as the standard Dublin Core metadata fields.

Modifying the fields of an existing schema

Modifying an existing schema field is possible using the syntax schema['<field_name>'].attribute = value. For example, to change the label of the description field widget (already available in BaseSchema), you can write (in your defined schema definition that reuses BaseSchema):

schema['description'].widget.label = u'Summary'

The fields in the schema are ordered, and normally first fields come first in "add" and "edit" forms. To rearrange a field within the schema use the moveField method:

  • Place it before a specific field: schema.moveField('<field_to_move>', before='<field_to_place_it_before>')
  • Place it after a specific field: schema.moveField('<field_to_move>', after='<field_to_place_it_after>')
  • Place it at the top of the schema: schema.moveField('<field_to_move>', pos='top')
  • Place it at the bottom: schema.moveField('<field_to_move>', pos='bottom')
  • Place it in a specific position: schema.moveField('<field_to_move>', pos=0)

 

1.3. What is ATContentTypes?

ATContentTypes is the Plone core product that provides the default content types (since Plone 2.1).

One of the major changes introduced in Plone 2.1 was that the core content types (Page, Image, etc) were changed from being based on stock CMF types, to using Archetypes. The new core types are housed in the ATContentTypes product.

ATContentTypes introduces a number of base classes and tools that provide common "Plone-ish" behaviour. This includes things like support for the "display" menu and the "more..." menu and restrictions for the "add item" menu.

You can use ATContentTypes' base classes and tools in your own products. The RichDocument tutorial covers the core techniques, and is probably a good place to go when you have finished this reference.

2. A simple AT Product

A semi-realistic example Archetypes-based content type product.

2.1. Introduction

Introducing a sample AT Product and the contents of the tutorial.

In this part of the manual, we discuss a sample AT Product to explain CMF/Archetypes practices. We will be building a product called example.archetype, which will implement a content type (InstantMessage) that members with specific rights can use to add messages readable by other members. However, as you may have guessed, this is more a learning example than a usable product for a real website application.

What is a Product ? A product - a Zope product to be precise - is a third party add-on that can be integrated to provide additional functionality. It is a code package written using the Python language and conventions.

In order to understand this section you will need to have some prior knowledge of working on the file system and programming protocols common to Python and Zope.

The example.archetype product features the following CMF and Archetypes capabilities:

  • basic fields and widgets;
  • defining and using a vocabulary for a field with a selection widget;
  • defining specific "Add" permissions for the contents.

The code of the product can be downloaded here: http://plone.org/products/example.archetype/

2.2. Product package layout

Conventions and techniques for organizing the package for an AT product.

Following Zope, Plone and AT's conventions, the content of our example product pakage will look like this:

- __init__.py
- configure.zcml
- config.py
- interfaces.py
- content
    - __init__.py
    - message.py
- profiles
    - default
- browser
    - __init__.py
    - configure.zcml
    - instantmessage.pt
- tests
    - __init__.py
    - base.py
    - test_setup.py

What is the purpose of these files and directories?

  • __init__.py: The usual "Python package" initialization module;
  • configure.zcml: Using Zope's new Configuration Markup Language (ZCML), this file configures the services or behaviour the Zope server needs to load at startup;
  • config.py: Provides configuration variables for the product;
  • interfaces.py: Where you define interfaces describing what the packages' classes will do;
  • content: Contains the modules providing the implementation of the content types. In this case, it contains the message.py file where the 'InstantMessage' class should be defined;
  • profiles/default: Contains a set of XML files that are needed to provide the settings that will be used by Plone's Quick-Installer tool when installing the product within Plone; this is what we call an Extension Profile, an artifact of Zope CMF's GenericSetup technology. Note that this replaces the old way of doing based on the Extensions/Install. More precisely, since Plone 3.0, you do not need that old-style technique;
  • browser: The sub-package where the developer can add specific presentation code such as browser views and templates; the contained configure.zcml is used to provide these components registration.
  • tests: Contains the unit tests code for the product.

Now we will go through the files one by one and add what we need to produce our application.

2.3. The interfaces module

The module where you define interfaces describing what your content class(es) will do.

Why do you need interfaces?

Interfaces are useful to describe what a class will do. They are a kind of contract between a class and the components that class interact with. Starting a content management functionality package with writing interfaces is recommended practice as it helps document your code. In addition to that, Zope Component Architecture (ZCA) allows us to use interfaces as components for adapting a class (which is useful as new user requirements appear) and thus specializing its behaviour.

The interface for the Instant Message class

This is done by convention in the interfaces.py file, that you need to add at the root of the package.

First, we need an import from Zope's zope.interface module, which is included into Zope 2's distribution since version 2.8:

    from zope.interface import Interface

Following ZCA naming conventions (interface names start with an I), we define the IInstantMessage interface we need for the InstantMessage class that we will define later:

    class IInstantMessage(Interface):
        """
        Interface for the InstantMessage class.
        """

That's it!

We could add attribute definitions to it using the zope.interface.Attribute class, but this is not mandatory. When an interface is defined as above, without any function nor attribute, we call it a "marker interface" meaning that it will be used simply to "mark" the instances of the class that implements it.

More information about interfaces in the context of Archetypes can be found in the b-org tutorial - Interfaces section. For a detailed presentation of interfaces and their usage patterns, read the doctests document available from Zope's documentation site.

2.4. The configuration module

The configuration details for your content type, in config.py.

First, we have to import a class from Archetypes:

from Products.Archetypes.atapi import DisplayList

Displaylist is a data container we use when displaying pulldowns/radiobuttons/checkmarks with different choices. Let's say we wanted priorities on our instant messages, and we wanted those to be High, Normal and Low. We will specify these later in the file.

The next two lines set the project (Product in Zope) name, and point to the skin directory. PROJECTNAME should reference the name of the package: example.archetype.

PROJECTNAME = "example.archetype"

Now, we need to specify our 'Priority' pulldown. It should look like this, using the DisplayList utility class that Archetypes has provided for exactly that purpose:

MESSAGE_PRIORITIES = DisplayList((
    ('high', 'High Priority'),
    ('normal', 'Normal Priority'),
    ('low', 'Low Priority'),
    ))

Python notes:

  • The reason for double parantheses is that DisplayList is a class that you pass a tuple of tuples to.

 We also need to define the "Add" permission(s) for the content type(s):

ADD_CONTENT_PERMISSIONS = {
    'InstantMessage': 'example.archetype: Add InstantMessage',
 }

We recommend using the standard way of naming permissions: '<ProductName>: <Permission>'. This will group the related permissions together within the ZMI (Security tab), and allow the Administrator to recognize which permissions belong to which Product.

Note that, unless you have an advanced case which needs custom security settings, you don't need to define your own permissions for the "edit" and "view" of the content. In this simple case you will just reuse, in the modules where needed, the generic permissions defined in CMFCore.permissions: "View", "Modify portal content"...

2.5. The startup module

The initialization module (__init__.py) provides the script that is run when Zope is started.

Before starting the usual Zope product initialization code, we need to define a Message Factory for when this product is internationalized.

from zope.i18nmessageid import MessageFactory

exampleMessageFactory = MessageFactory('example.archetype')

The defined MessageFactory object will be imported with the special name "_" in most modules, and strings like _(u"message") will then be extracted by i18n tools for translation.

Now, we import some useful stuff from the Archetypes API:process_types is useful to get the product's content types, associated constructors, and Factory Type Information (FTI) data structures, while listTypes can be used to list the types available in the product.

We also need to import the utils module from CMFCore to be able to use its ContentInit class later.

from Products.Archetypes.atapi import process_types
from Products.Archetypes.atapi import listTypes

from Products.CMFCore import utils

Python notes:

  • Factory Type Information (FTI): Part of a CMF portal's configuration, the FTI for a content type is the data structure that holds the information needed to expose a content type within the portal. From the integrator's perspective, the FTI is the object (Factory-based Type Information object) within the portal_types component that tells CMF and Plone how to create a content from the type and how to display it.

  • How exactly does 'listTypes' work: See those registerType() calls in your content type modules? Notice how we also import those modules (but do nothing with the import) in the 'content' package's __init__.py. The registerType() call tells AT about the type so that listTypes() can find it later.

One of the important import steps : we import everything that is defined in the content sub-package, i.e. all its modules:
from content import message
Now, we import the configuration module, in order to have access to the variables it contains, such as the "Add" permission setting:
import config

Now for the real action. You define a function that is required by Zope and CMF internals to initialize our content type(s):

def initialize(context):

The first part of the code of this function generates the content types, the constructors and the Factory-based Type Informations (or FTIs) required to make your types work with the CMF:

    content_types, constructors, ftis = process_types(
        listTypes(config.PROJECTNAME),
        config.PROJECTNAME)

The second part instantiates an object of the class ContentInit (from CMFCore), and registers your types in the CMF:

    utils.ContentInit(
            "%s Content" % config.PROJECTNAME,
            content_types      = content_types,
            permission         = config.ADD_CONTENT_PERMISSIONS['InstantMessage'],
            extra_constructors = constructors,
            fti                = ftis,
            ).initialize(context)

Handling several content types

There is a better way to write the code that initializes the content type class with its "Add" permission and constructor, so that it still works if you define several content types. This is useful if you plan to later augment your product with additional types.

Here is the improved code:

def initialize(context):

    content_types, constructors, ftis = process_types(
             listTypes(config.PROJECTNAME), 
             config.PROJECTNAME)


    # We want to register each type with its own permission,
# this will afford us greater control during system
# configuration/deployment (credit : Ben Saller)

    allTypes = zip(content_types, constructors)
    for atype, constructor in allTypes:
        kind = "%s: %s" % (config.PROJECTNAME, atype.portal_type)
        utils.ContentInit(kind,            
                          content_types      = (atype,),
                          permission         = config.ADD_CONTENT_PERMISSIONS[atype.portal_type],
                          extra_constructors = (constructor,),            
                          fti                = ftis,
                          ).initialize(context)

Python notes:

  • We can use the "ADD_CONTENT_PERMISSIONS[atype.portal_type]" construct because ADD_CONTENT_PERMISSIONS references a dictionary in which the keys are the potential content types names.

  • The zip() function is a Python built-in that pairs up elements of two lists. In this case, "allTypes" will be a list of tuples containing a content type from "content_types" and the corresponding constructor from "constructors".

  • If you have several content types, you should not forget to import each content module, as is done for the message example discussed here !

 

2.6. The content package and its modules

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

 

2.7. Adding a custom view for the content

Providing the custom presentation template for the InsantMessage, using Zope's browser layer mechanism.

The browser layer concept

A browser layer is a concept introduced by Zope Component Architecture (Zope 3), and which can be used in Plone. It is useful for registering views and resources (images, CSS, JS) for the site, in a way that they can override default elements (which are implicitly registered for the default browser layer) or be overriden when needed, even through the ZMI. A browser layer is similar in purpose to a CMF skin layer, but is implemented differently.

To add a browser layer to your product, you need 3 steps:

  • Define the marker interface for the browser layer (for example, example.archetype.interfaces.IInstantMessageSpecific.)
  • Add an XML file in your extension profile named browserlayer.xml providing the browser layer settings to the site. (This step is covered later as part of the various product setup details.)
  • Register (using ZCML) your browser views, templates and resources.
For more about browser layer techniques, check this tutorial.

Defining the browser layer interface

Add a marker interface for the browser layer (in interfaces.py):

from plone.theme.interfaces import IDefaultPloneLayer class IInstantMessageSpecific(IDefaultPloneLayer):     """Marker interface that defines a Zope 3 skin layer for this product.     """

Adding and registering the browser template

To provide a custom view template for your content type, you need a page template called instantmessage.pt in the browser/ directory, and a ZCML declaration in the configure.zcml to associate the template to the IInstantMessageSpecific Zope 3 skin layer.

<configure xmlns="http://namespaces.zope.org/zope"     xmlns:browser="http://namespaces.zope.org/browser"     i18n_domain="example.archetype" >     <browser:page         for="example.archetype.interfaces.IInstantMessage"         layer="example.archetype.interfaces.IInstantMessageSpecific"         name="instantmessage_view"         template="instantmessage.pt"         permission="zope2.View"         /> </configure>

Here is the example template code:

<html metal:use-macro="here/main_template/macros/master"
      i18n:domain="plone" >
<body>

<div metal:fill-slot="main"
     tal:define="priority here/getPriority;
                 priority_color python:(priority == 'high' and 'red') or (priority == 'low' and 'green') or ''" >

        <h1 tal:content="context/Title"
            tal:attributes="style string:color:$priority_color" >
          Title
        </h1>

        <p tal:content="structure here/getBody" />          

        <div class="documentByLine">
          Message by <span tal:content="context/Creator" /> 
          with <strong tal:content="priority" /> priority.
          -
          <span tal:replace="python:here.toLocalizedTime(context.CreationDate(),long_format=1)" />
        </div>
    
</div>

</body>
</html>

Python notes:

  • The new methods we use on the content object (getPriority, getBody, etc), called the "accessors", are generated by Archetypes as part of its internal mechanisms, based on the field definition in the content schema; so if the field is called 'priority', there is a generated method called 'getPriority' responsible to return the stored value on the object. Note that the code of the method is not available somewhere for modification ; "generated" here means it is available in the server's memory, within Archetypes engine's registries, when the Zope server has started.

After the product installation step, which we still have to discuss (see later), Plone should be able to find this template and use it as the content object's default view when you invoke the content's URL.

2.8. Installing the product

Ensuring the product elements (types, browser layers, resources) are correctly installed.

In this part, we will provide the code to be executed when the integrator "adds", i.e. installs, the InstantMessage product to the Plone site. This aspect of the product code is called the "Extension Profile" (or "Setup Profile") and is managed under the hood by a machinery called GenericSetup.

For more about GenericSetup, its possibilities, and how a developer uses it, read the GenericSetup tutorial.

The setup profile files (profiles/default)

The setup profile is composed of a set of GenericSetup XML files containing setup declarations.

Type declaration and definition

First, we provide the files needed for adding the types to CMF's types registry (portal_types): types.xml and types/InstantMessage.xml.

In types.xml, within the <object name="portal_types" ... /> element, add the setup code for the type(s) you want to install:

<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
 <property
    name="title">Controls the available content types in your portal</property>
 <object name="InstantMessage"
    meta_type="Factory-based Type Information with dynamic views"/>
</object> 

The name property of the <object> node constitutes the called portal type name of the content-type, a CMF concept which supports two things:

  1. Dynamic typing: objects can change their content type during their lifetime. To do this use _setPortalTypeName(<type>).
  2. You can have arbitrarily many different content types using the same base class (and having therefore the same meta_type) but differing in their Factory Type Information (FTI) settings.

The portal type name was formerly set in a content-type class attribute called portal_type, which is no longer necessary.

The name of the file inside the profiles/default/types folder must match the portal type name, with spaces converted to underscores whenever necessary. So, in types/InstantMessage.xml, add the code for the InstantMessage FTI object:

<?xml version="1.0"?>
<object name="InstantMessage"
   meta_type="Factory-based Type Information with dynamic views"
   i18n:domain="example.archetype" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  <property name="title" i18n:translate="">Example AT - InstantMessage</property>
  <property name="description"
    i18n:translate="">An example type (InstantMessage) discussed in the AT Developer Manual.</property>

In these first lines we give the content-type a title and a description.

The title property indicates the user-friendly name of the content-type. This is what's supposed to be used in the user interface, and can be accessed using the <fti>.title_or_id() or the Type() methods, which both return the content-type title if it exists or the content-type id otherwise. Like portal type, this property was formerly set in a the content-type class attribute called archetype_name, which is no longer neccessary.

  <property name="content_meta_type">InstantMessage</property>
  <property name="content_icon">document_icon.gif</property>
  <property name="product">example.archetype</property>
  <property name="factory">addInstantMessage</property>

The meta_type property of the object is a Zope concept to organize object classification or containment. For historical reasons, it is used in CMF in some places because first versions of CMF didn't have today's portal_type. Also note that Archetypes uses the content-type class name as the meta_type value, unless given explicitly.

The content_icon property specifies the icon image file which will be shown in the Plone UI for this content-type. This icon image file must be accessible from the context of the content-type, and therefore should be placed into a CMF skin layer (the CMF way) or in a browser resource directory (the Zope 3 way).

The factory property indicates the factory function which will be used to create and initialize new content objects of this type. This factory is automatically generated by the Archetypes framework, when the product is initialized (via the code in the startup module), and is always named add<content-meta-type>. The factory is also associated with a certain product by means of the product property.

  <property name="immediate_view">atct_edit</property>
  <property name="global_allow">True</property>
  <property name="filter_content_types">False</property>
  <property name="allow_discussion">False</property>

The global_allow property determines if the content-type will be available to be added from anywhere in the site.

The filter_content_types property, paired with allowed_content_types, controls what content-types will be addable inside the current one.

With allow_discussion, we specify whether or not comments will be allowed by default on this content-type.

  <property name="default_view">@@instantmessage_view</property>
  <property name="view_methods">
    <element value="@@instantmessage_view" />
  </property>
  <alias from="(Default)" to="@@instantmessage_view" />
  <alias from="edit" to="atct_edit" />
  <alias from="sharing" to="@@sharing" />
  <alias from="view" to="@@instantmessage_view" />

Here we define CMF views (templates) and aliases that map content-type methods to views.

  <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>

The <action> elements register type-specific actions for the content-type. The object category makes the render as tabs in the Plone UI.

  • The url_expr is a TALES expression that defines the URL from where the action will be triggered and should match one of the method aliases defined above. Hence, the edit action points to string:${object_url}/edit, which means that if you are at /path/to/object and click edit, you will go to /path/to/object/edit. /edit then gets recognized as a method alias, which points to the page template atct_edit, causing Zope to render /path/to/object/atct_edit.
  • The <permission /> element specifies a guard permission for this action. If the user's role doesn't have this permission, the action won't be available and the corresponding action tab won't be shown.
  • In addition to the former criteria, the condition_expr is a TALES expression which will be evaluated to decide if the action is available or not.
  • The visible attribute indicates wheter the action tab will be visible or hidden. If it's set to False, the tab won't appear even when the action is available, but the exposed page will still be accesible from the associated URL.
Notes:
  • Defining new content-type actions this way, i.e. using GenericSetup, supersedes the old updateActions function from ATContentTypes.content.base.
  • Don't worry. You don't have to type all this XML each time you create a new content-type; since most of it is boilerplate (XML is very verbose) you can copy & paste an already working example (like the CMFPlone ones) and modify only the changing bits.

Type factory

We also need the file useful for setting the type against Plone's factory tool (portal_factory): factorytool.xml. This is needed so that when a user adds a content object and then clicks Cancel in the edit form, a stale object won't be lying around.)

<?xml version="1.0"?>
<object name="portal_factory" meta_type="Plone Factory Tool">
 <factorytypes>
  <type portal_type="InstantMessage"/>
 </factorytypes>
</object>

Roles - Permissions mapping

For our content type(s) to be usable, we need to assign the required "Add" permission to the Plone site's default roles: Contributor, Owner, and Manager. This is done using the rolemap.xml file as follows:

<?xml version="1.0"?>
<rolemap>
    <permissions>
        <permission name="example.archetype: Add InstantMessage" acquire="True">
          <role name="Manager"/>
          <role name="Owner"/>
          <role name="Contributor"/>
        </permission>
    </permissions>
</rolemap>

Browser skin layer

In order to install our browser skin layer, we also add a browserlayer.xml file with the following code:

<?xml version="1.0"?>
<layers>  
  <layer name="example.archetype"
         interface="example.archetype.interfaces.IInstantMessageSpecific" />
</layers>

Registering our setup profile

This last step ensures everything can work. We update the package's configure.zcml file with the code snippet that will load the extension profile:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:five="http://namespaces.zope.org/five"
    xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
    i18n_domain="example.archetype" >

   <five:registerPackage package="." initialize=".initialize" />

   <include package=".browser" />

   <genericsetup:registerProfile
      name="default"
      title="Example Archetype content - InstantMessage"
      directory="profiles/default"
      description="Extension profile for Example AT - InstantMessage"
      provides="Products.GenericSetup.interfaces.EXTENSION"
      />

</configure>

Restarting Zope

Now that you have a first version of your product ready to be tested, and installed via your buildout, you need to (re)start Zope.

Quick-installing the product

Back in the Plone configuration (or Plone control panel), when you visit the "Add/Remove Products" interface or the portal_quickinstaller tool through the ZMI (at the root of the site), you can see the product show up under the category of "installable products".

Select and click the button to install the product. If everything goes fine, the product should be installed, and you're ready to start using it!

2.9. Basic integration tests

No product is complete without tests.

To build high-quality software, you must provide automatic tests - often known as "unit" tests (though tests for Archetypes products tend to be "integration" tests, strictly speaking).

The tutorial on testing and test-driven development is essential reading if you want to write high-quality software (and you don't know the techniques it advocates already). Please refer to it for details.

The example.archetype product contains basic tests that prove that the product is properly installed, that it registers its types, and that an InstantMessage object can actually be instantiated. If it contained more functionality, there would have been more tests, but even simple integration tests like this can be surprisingly useful - if you accidentally broke the content type with some change, you'd notice that it failed to install or instantiate.

The tests are in the "tests" directory. The file "base.py" contains some base classes that are used for tests, to ensure the site is properly set up:

import unittest

from zope.testing import doctestunit
from zope.component import testing
from Testing import ZopeTestCase as ztc

from Products.Five import zcml
from Products.Five import fiveconfigure
from Products.PloneTestCase import PloneTestCase as ptc
from Products.PloneTestCase.layer import PloneSite
from Products.PloneTestCase.layer import onsetup

@onsetup
def setup_product():
    """Set up the package and its dependencies.
    
    The @onsetup decorator causes the execution of this body to be deferred
    until the setup of the Plone site testing layer. We could have created our
    own layer, but this is the easiest way for Plone integration tests.
    """
    
    fiveconfigure.debug_mode = True
    import example.archetype
    zcml.load_config('configure.zcml', example.archetype)
    fiveconfigure.debug_mode = False
        
    ztc.installPackage('example.archetype')
    

setup_product()
ptc.setupPloneSite(products=['example.archetype'])


class InstantMessageTestCase(ptc.PloneTestCase):
    """Base class for integration tests.

    This may provide specific set-up and tear-down operations, or provide
    convenience methods.
    """

The actual tests are in "test_setup.py":

from base import InstantMessageTestCase
from example.archetype.interfaces import IInstantMessage

class TestProductInstall(InstantMessageTestCase):

    def afterSetUp(self):
        self.types = ('InstantMessage',)

    def testTypesInstalled(self):
        for t in self.types:
            self.failUnless(t in self.portal.portal_types.objectIds(),
                            '%s content type not installed' % t)

    def testPortalFactoryEnabled(self):
        for t in self.types:
            self.failUnless(t in self.portal.portal_factory.getFactoryTypes().keys(),
                            '%s content type not installed' % t)

class TestInstantiation(InstantMessageTestCase):

    def afterSetUp(self):
        # Adding an InstantMessage anywhere - can only be done by a Manager or Portal Owner
        self.setRoles(['Manager'])
        self.portal.invokeFactory('InstantMessage', 'im1')

    def testCreateInstantMessage(self):
        self.failUnless('im1' in self.portal.objectIds())

    def testInstantMessageInterface(self):
        im = self.portal.im1
        self.failUnless(IInstantMessage.providedBy(im))

def test_suite():
    from unittest import TestSuite, makeSuite
    suite = TestSuite()
    suite.addTest(makeSuite(TestProductInstall))
    suite.addTest(makeSuite(TestInstantiation))
    return suite

To run these tests within your buildout environment:

./bin/instance test -s example.archetype

You may see output like:

 Ran 4 tests with 0 failures and 0 errors in 0.119 seconds.

If there was an error with one or more of the tests, you'd be told here!

Please refer to the testing tutorial for more about writing tests - and writing good tests - and how to run them.

3. Other useful Archetypes features

Complementary features you'd be pleased to know about.

3.1. How to use events to hook the Archetypes creation process

Times have changed since the days of at_post_create_script(). Here is the way to hook into Zope3 (or Five's) event system in order to execute code during the Archetypes content creation and or editing process.

In the old days the only way to execute code during the object creation process for Archetypes was to add a method to your content type called at_post_create_script. In this script you would add any code that should execute after Archetypes was done creating the object.

The new method for hooking the Archetypes object creation and editing process is to use Zope3 style events, like Products.Archetypes.interfaces.IObjectInitializedEvent.

Prerequisites

Have a content type handy so we can add a post creation hook to it. To learn how to create a content type, check previous sections of this manual.

We're going to use a content type called ExampleContent with the interface IExampleContent for this how to. The code structure will look like this:

tutorial/configure.zcml
tutorial/interfaces.py
tutorial/content/examplecontent.py

Step by step

First let's create the interface for our ExampleContent type. In interfaces.py, add:

from zope.interfaces import Interface

class IExampleContent(Interface):
    ''' Interface for the ExampleContent type
    '''

You can store the implementation for your event handlers anywhere but for the purpose of this example we're going to put it in the same module as the ExampleContent type:

from zope.interface import implements
from Products.ATContentTypes import atct

def addSubFolder(obj, event):
    obj.invokeFactory(type_name='Folder', id='subfolder')

class ExampleContent(atct.ATFolder):
    implements(IExampleContent)
    portal_type = archetype_name = 'ExampleContent'  # <-- this is no longer needed with GenericSetup.

All we need to do now is register the addSubFolder method as a handler for Products.Archetypes.interfaces.IObjectInitializedEvent and for anything implementing the IExampleContent interface. We do this in a configure.zcml file:

<subscriber for=".interfaces.IExampleContent
                 Products.Archetypes.interfaces.IObjectInitializedEvent"
            handler=".content.examplecontent.addSubFolder" />

Notice that there are two interfaces in the "for" attribute. This is because we are register a multi-adapter. Now when you add an ExampleContent type the addSubFolder method will be executed after Archetypes has created the object. The object itself will be passed to the handler and we can use the object reference to make additional modifications, in this case adding a sub folder.

You can register as many handlers as you need.

Warnings from your future

Having implemented all of your content type's event hooks you might then run off and try using invokeFactory somewhere in your code only to realize that your IObjectInitializedEvent handlers are not being executed. This is because invokeFactory does not notify Zope's event system that new objects are being created. You have to provide these notifications yourself. So here is an example:

import zope.event
from Products.Archetypes.event import ObjectInitializedEvent
some_folder.invokeFactory(type_name='ExampleContent', id='foobar')
obj = getattr(some_folder, 'foobar')
zope.event.notify(ObjectInitializedEvent(obj))

This will both create your object and invoke any IObjectInitializedEvent handlers you have registered. Notice that we are importing ObjectInitializedEvent, not the interface IObjectInitializedEvent. We want to actually instantiate an event passing it our newly created object as the single parameter and then pass the event to zope.event.notify. From there, Zope takes care of figuring out which handlers need to execute.

Further information

The IObjectInitializedEvent is fired once during the objects creation process. To hook the editing process for an object use IObjectEditedEvent.

The Sending and handling events tutorial is a little out of date but provides a broader explanation of the underlying mechanics. Walking through Five to Zope 3 - Events is another great introduction to events handling. 

 

4. Fields

This section describes what Archetypes Fields are, how they work, and how to use them. It also contains reference sections listing all available field types and the related widgets.

4.1. Fields Reference

Attributes of standard Archetypes fields.

Topics

Common Field Attributes

BooleanField

ComputedField

CMFObjectField

DateTimeField

FileField

FixedPointField

FloatField

ImageField

IntegerField

LinesField

ReferenceField

StringField

TextField

 

 

    Common Field Attributes

    These attributes are common to nearly all fields. Field-specific attributes follow, and are listed by field. Particular fields have different defaults, types, and some other specialized attributes.

    NameDescriptionPossible ValuesDefault
    accessorThe name of a class method that will return the value of the field. Use this to change how the field is retrieved. If you don't provide a custom method name here, a default accessor, named getYourFieldName, is going to be created that just returns the value of the Field.
    A class method name; for example, specialGetMethodNone
    default
    The default value for the field.
    Type should be appropriate to the field.
    None
    default_method
    The name of a class method returning a value for the field.A class method name; for example, getSpecialDescription.
    None
    edit_accessorThe name of a class method that returns the raw value of a field.Any method name (for example, rawGetMethod).
    None
    enforceVocabularyDetermines whether or not values outside the vocabulary will be accepted. If True, Archetypes will validate input for the field against the vocabulary. Only values already in the vocabulary will be accepted.
    True or False.
    False
    index
    (Plone < 3 only)
    If you want this field to be placed in its own catalog index, then specify the type of index here as a string. If you append :schema onto the end of the schema, then this will also be added as a metadata column. (The actual index will be on the field accessor, typically "getFieldName".)
    Ignored in Plone 3+; use GenericSetup profile for similar functionality.
    The name of any index, such as KeywordIndex or KeywordIndex:schema.
    None
    index_methodMay be used to specify the method called when indexing a field. Use '_at_accessor' to use the default accessor, '_at_edit_accessor' to use the edit accessor, or the name of a method returning the value to be indexed._at_accessor, _at_edit_accessor, getIndexAccessor and getIndexAccessorName
    _at_accessor
    languageIndependent
    Flag for Fields that are independent of the language, such as dates. True tells LinguaPlone that no translation is necessary for this field.True or FalseFalse
    isMetadata
    Marks metadata fields. This is currently only needed as a convenience for the filterFields method of Schema. Fields marked as metadata are not displayed in the uncustomized base view.True or FalseFalse
    mode
    The read/write mode of field, as a string; the default is to be read and write. Accessors will not be created without the read mode, and Mutators will not be created without the write mode.
    For read only: r, for write only: w, for read and write: rw.
    rw
    multiValued
    Set this to True if the field can have multiple values. This is the case for fields like multiple-selection lists that allow the selection of multiple values.True or False.
    False
    mutator
    The string name of a class method that changes the value of the Field. If you don't provide a special method name here, a default mutator is generated with the name 'setYourFieldName' to simply store the value.A class method name; for example, specialSetMethod.
    None
    nameA unique name for this field. Usually specified as the first item in the field definition.
    Any string. Strongly recommended: lowercase, no punctuation or spaces, conforming to standard Python identifier rules. For example, description, user_name, or coffee_bag_6.
    No default.
    primaryIf True, this will be the field that used for File Transfer Protocol (FTP) and WebDAV requests. There can be only field that does this; if multiple are defined, the first one in the schema will be used. You normally set this for the main body attribute. Only used for TextField and FileField field types.True or FalseFalse
    read_permission
    The permission required for the current user to allowed to view or access the field. Only useful if the read mode is activated. This read permission is checked when rendering the widget in read mode.A permission identifier imported from Products.CMFCore.permissionsView
    required
    Specifies that some value for this field required.True or False.False
    schemata
    Use named schematas to organize fields into grouped views.A short string that labels the group.
    default
    searchable
    Specifies whether or not the field value will be indexed as part of the SearchableText for the content object. SearchableText is what is checked by the portal's main search.True or False.False
    storage
    The storage mechanism for the field. The default is Attribute Storage, which stores the field as an attribute of the object.Any valid storage object such as AttributeStorage or SQLStorage. You can find these in the Archetypes Application Programming Interface (API).
    AttributeStorage
    type
    Provided by the field class.. Should never be changed in a Schema.None
    None
    validators
    A list or tuple of strings naming validators that will check field input. If you only have one validator, you may specify it as a string.
    Validators may also be instances of a class implementing the IValidator interface from from Products.validation.interfaces.IValidator. Providing a class instance allows you more flexibility as you may set additional parameters.
    Validators are checked in order specified.
    The names of validators registered via Products.validation; for example, isEmail.()
    vocabulary
    Provides the values shown in selection and multi-selection inputs. This may be specified as a static list or as the name of a class method returning the choice list.
    A list of strings (in which case keys and values will be the same); a list of 2-tuples of strings [("key1","value 1"),("key 2","value 2"),...]; a Products.Archetypes.utils.DisplayList. Or, the name of a class method returning any of the above.()
    vocabulary_factoryLike the vocabulary attribute, in Plone 3 provides the values shown in selection and multi-selection inputs. A string name of a Zope 3 style vocabulary factory (a named utility providing zope.schema.interfaces.IVocabularyFactory)None
    widgetThe widget that will be used to render the field for viewing and editing. See the widget reference for a list of available widgets.
    An instance of a widget; for example, StringWidget().
    StringWidget()
    write_permission
    The permission required for the current user to edit the field value. Only interesting if the write mode is activated. The write permission is checked when rendering the widget in write mode.A permission identifier imported from Products.CMFCore.permissionsModifyPortalContent

    Standard Fields

     

    BooleanField

    Simple storage of True or False for a field.

    Standard properties
    NameTypeDefaultDescriptionexample values
    widgetwidgetBooleanWidget Implemented as a check box.
    defaultbooleanFalse

    type
    boolean

    Note: The required attribute for the boolean field is often confusing. It does not require that the box be checked. Use a validator if you need to require the box be checked.

    ComputedField

    Read-only field, whose content cannot be edited directly by users, but is computed instead from a Python expression. For example, it can be the result of an operation on the contents from some other fields in the same schema, e.g. calculating the sum of two or more currency amounts, or composing a full name from first name and surname.
    This field is usually not stored in the database, because its content is calculated on the fly when the object is viewed.

    Standard properties
    NameTypeDefaultdescriptionsome possible values
    widgetwidget ComputedWidget
    storagestorage ReadOnlyStorage

    type
    computed

    modestring r

    Special properties
    NameTypeDefaultDescription some possible values
    expression

    Evaluated on the object to compute a value.

     

    CMFObjectField

    Used for storing values inside a CMF Object, which can have workflow. Can only be used for BaseFolder-based content objects.

    Standard properties
    NameTypeDefaultdescriptionsome possible values
    widgetwidget FileWidget
    storagestorage ObjectManagedStorage

    type
    object

    Special properties
    NameTypeDefaultDescriptionsome possible values
    portal_type
    File

    workflowable
    True

    default_mime_type
    application/octet-stream

    DateTimeField

    Used for storing dates and times.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    widgetwidget CalendarWidget
    defaultDateTime


    type
    datetime

    Note: The default for the DateTimeField needs to be specified as a DateTime object. If you need to set the current date/time as the default, you'll need to use the default_method attribute to specify a class method returning the current date/time as a DateTime object.

    Example:

    from DateTime.DateTime import DateTime
    
    ...
    
    # inside the schema definiton
        DateTimeField('dateAdded',
            searchable = 1,
            required = 0,
            default_method = 'getDefaultTime',
            widget = CalendarWidget(
                label = 'Date Added'
            ),
        ),
    
    ...
    
    def getDefaultTime():  # function to return the current date and time
        return DateTime()
    


    FileField

    Storage for large chunks of data such as plain-text files, office-automation documents, and so on.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    widgetwidget FileWidget
    defaultstring


    type
    file

    Special properties
    NameTypeDefaultDescriptionsome possible values
    primary
    False

    default_content_type
    application/octet

    primaryboolean FalseSet this True to mark the field as primary for FTP or WebDAV.

    Note: File field values are stored as strings. It's a common practice to use streams to read/write the values as if they were files.

     

    FixedPointField

    For storing numerical data with fixed points.

    Standard properties
    NameTypeDefaultDescription some possible values
    widgetwidget DecimalWidget
    validatorsvalidators isDecimal

    defaultstring 0.00

    type
    fixedpoint

    Special properties
    NameTypeDefaultDescriptionsome possible values
    precision
    2

     

    FloatField

    For storing numerical data with floating points.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    defaultstring0.0

    type
    float

     

    ImageField

    Stores an image and allows dynamic resizing of the image.

    Standard properties
    NameTypeDefaultDescription some possible values
    widgetwidget ImageWidget
    defaultstring


    type
    image

    allowable_content_typestuple of MIME strings Specifies the types of images that will be allowed. ('image/gif','image/jpeg','image/png') ('image/jpeg','image/png')

    Note: Image field values are stored as strings. It's a common practice to use streams to read/write the values as if they were files.

    Special properties
    NameTypeDefaultDescriptionsome possible values
    original_sizetuple (w,h) None The size to which the original image will be scaled. If it's None, then no scaling will take place; the original size will be retained. Caution: the aspect ratio of the image may be changed.(640,480)
    max_sizetuple (w,h) None If specified then the image is scaled to be no bigger than either of the given values of width or height. Aspect ratio is preserved. Useful to prevent storage of megabytes of unnecessary image data.(1024,768)
    sizesdict {'thumb':(80,80)} A dictionary of scales in which the image will be available. Dictionary entries should be of the form 'scaleName':(width,height).{ 'mini' : (80,80), 'normal' : (200,200), 'big' : (300,300), 'maxi' : (500,500)}
    pil_qualityinteger 88 A JPEG quality setting (range 0 to 100). Lower numbers yield high compression and low image quality. High numbers yield low compression and better quality.50 (a medium quality)

    Using Image Scales

    To display the original image (possibly rescaled if you used original_size or max_size attributes), you may use a URL like:
    http://url_of_content_object/imageFieldName
    as the SRC attribute of an IMG tag where url_of_content_object is the URL of the content object and imageFieldName is the name of the image field.

    To display one of the scales, use a URL like:
    http://url_of_content_object/imageFieldName_scale
    where scale is one of the keys of the sizes dictionary.

    Attention: The direct attribute access as shown above works only together with AttributeStorage, which will be used by default. To avoid heavy memory consumption on sites with many images it is recommended to use AnnotationStorage for the ImageField.

    You may also generate a ready-to-insert IMG tag with the python code:

    obj.getField('image').tag(obj, scale='mini')
    
    if obj is your content object, image the name of your image field, and mini the name of your scale.

     

    You may rescale to other sizes than those in the sizes field attribute with code like:

    obj.getField('image').tag(obj, height=480, width=640, alt='alt text',
                css_class='css_class_selector', title='html title attribute')
    

     

    IntegerField

    For storing numerical data as integers.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    widgetwidget IntegerWidget
    defaultinteger 0

    type
    integer

    Special properties
    NameTypeDefaultDescription some possible values
    size
    10 Sets the size of the input field.

     

    LinesField

    Used for storing text as a list, for example a list of data such as keywords.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    widgetwidget LinesWidget
    defaultstring ()

    type
    lines

     

    ReferenceField

    Used for storing references to other Archetypes Objects.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    widgetwidget ReferenceWidget
    index_method
    _at_edit_accessor

    type
    reference

    multiValuedboolean False Set multiValued True to allow multiple references (one-to-many), or False to allow only a single reference (one-to-one).
    Special properties
    NameTypeDefaultDescriptionsome possible values
    relationship

    Specifes an identifier for the type of relationships associated with the field. This should be unique within your content type, but has no larger meaning. A ReferenceField allows you to edit the set of references with a particular relationship identifier from the current content object to other objects.'KnowsAbout', 'Owns', 'WorksWith'
    allowed_typestuple of portal types () Determines all the portal types that will be searched to find objects that the user can make a reference to. It also specifies the Types that should be allowed to be added directly from the reference widget. This is only activated if the addable property is set. An empty list or tuple will allow references to all portal types.('Document', 'File')
    allowed_types_methodstring None A string containing the name of a class method that will return a list of portal types to which references are allowed.
    vocabulary_display_path_boundinteger 5 Sets a limit for presentation of reference items. Up to this limit, only titles are displayed. Above the limit, the path to the referenced object is also displayed. The idea is that if there are a large number of referenced items, the user will need help to differentiate them.
    vocabulary_custom_labelstring None A string containing a python expression that will be evaluated to get the displayed text for a referenced item. Your expression may use the variable "b" which will be a reference to the catalog brain returned by the reference lookup."b.getObject().title_or_id()"

     

    StringField

    A field for plain-text, unformatted strings.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    defaultstring


    type
    string

    widgetwidget StringWidget
    Special properties
    NameTypeDefaultDescriptionsome possible values
    default_content_typestring MIME type text/plain
    Rarely changed.

     

    TextField

    A string field typically used for longer, multi-line strings. The string may also be transformed into alternative formats.

    Standard properties
    NameTypeDefaultDescriptionsome possible values
    defaultstring


    type
    text

    widgetwidget StringWidget
    Special properties
    NameTypeDefaultDescriptionsome possible values
    primaryboolean False Set this True to mark the field as primary for FTP or WebDAV.

    default_content_typestring MIME type text/plain A string designating MIME the default input type for the field.text/plain, text/html
    allowable_content_typestuple of MIME-type strings ('text/plain',) Used in the TextArea and Rich widgets to let the user choose between different text formats in which the content is entered.('text/plain', 'text/html',)
    default_output_typestring MIME type text/plain This is used by the accessor (get) method to and decides which MIME-Type the content should be transformed into if no special MIME-Type is demanded.'text/html', 'text/x-html-safe'

    4.2. Widgets Reference

    This page is a syntax reference and general guide for defining and using Widgets.

    Widget Attribute Topics

    Common Widget Attributes

    BooleanWidget

    CalendarWidget

    ComputedWidget

    DecimalWidget

    FileWidget

    ImageWidget

    InAndOutWidget

    IntegerWidget

    KeywordWidget

    LabelWidget

    LinesWidget

    MultiSelectionWidget

    PasswordWidget

    PicklistWidget

    ReferenceWidget

    ReferenceBrowserWidget

    RichWidget

    SelectionWidget

    StringWidget

    TextAreaWidget

    Common Widget Attributes

    The table below describes attributes common to nearly all widgets. Illustrations and special attributes listings for each of the standard widgets follows.

    NameDescriptionPossible Values
    condition
    A string containing a TALES expression to determine whether or not a field/widget is included on a view or edit page. This does not distinguish between view and edit mode.
    Your TALES expression may referenc the current context as 'object' and the Plone site root as 'portal'
    description
    Help or explanatory text for the field. Usually shown on the edit form under the label and above the input field.
    description_msgidThe i18n identifier for the description message. Used to translate the message. Should be unique within your product's i18n domain.'help_type_field'
    labelThe label that will appear in the field. Any string, for example, Start Date for a field start_date. Also label_msgid (takes string message ids for i18n.)
    label_msgidThe i18n identifier for the label message. Should be unique within your product's i18n domain.'label_type_field'
    i18n_domainThe i18n domain specifier for your product. This should be unique for your product, and will be used to find the translation catalogs for your product.'productname'
    modes The modes that this widget will be shown in; by default there are two modes: view and edit. A list of modes as strings; by default ("view", "edit").
    populate If this is enabled, the view and edit fields will be populated. Usually this is enabled, but for fields such as a password field, this shouldn't be the case. Usually this is true by default.True or False
    postback If this is enabled, then when an error is raised, the field is repopulated; for fields such as a password field, this shouldn't be the case. Usually this is True by default.True or False
    visible Determines whether or not the field is visible view and edit mode. This is a dictionary mapping the view mode to a string describing the visibility. Choices are visible, hidden (rendered in an HTML hidden form value), invisible (not rendered at all).For example, {'view': 'visible', 'edit': 'hidden' } means that the view will show, but the edit page will hide the value.

     

    Standard Widgets

     

    BooleanWidget

    Renders an HTML checkbox, from which users can choose between two values such as on/off, true/false, yes/no.

    booleanwidget.png 

    CalendarWidget

    Renders a HTML input box with a helper popup box for choosing dates.

    datetimewidget.png

    Special Properties

    NameTypeDefaultDescription
    formatstring
    Defines the date/time format using strftime, e.g. '%d.%m.%Y', for the view. (See the strftime section of the Python time documentation.
    If this is not specified, the long form of the portal's local time format is used.
    future_yearsinteger 5Specifies the number of future years offered by the year drop-down portion of the date widget. Do not use both future_year and end_year. (Plone 2.5+)
    starting_yearinteger1999The first year offered by the year drop-down. (Plone 2.5+)
    ending_yearinteger NoneThe final year offered by the year drop-down. Do not use both future_years and end_year. (Plone 2.5+)
    show_hmbooleanTrueShould the widget ask for a time as well as a date? (Plone 2.5+)

     

    ComputedWidget

    Generally used for ComputedField field type, it renders the computed value. Note that if your field has a vocabulary, and the field value is a key in that vocabulary, the widget will lookup the key in the vocabulary and show the result.

    Standard Properties

    NameTypeDefaultDescription
    modestuple ('view', 'edit')As ComputedField is a read-only field, this property can be used to prevent the widget from appearing in edit templates, by setting it to just ('view',).

     

    DecimalWidget

    In edit mode, renders an HTML text input box which accepts a fixed point value.

    Special Properties

    NameTypeDefaultDescription
    thousands_commasbooleanFalseIn view mode, formats the value to shows commas for thousands. For example, when thousands_commas is True, "7632654849635.02" is displayed as "7,632,654,849,635.02". (Note: this feature is not localized; it uses commas independent of locale.
    whole_dollarsboolean FalseShows whole dollars in view, leaving out the cents. Enter "1.123", and "$1" is shown. (Note: this feature is not localized; it uses the dollar sign independent of locale.)
    maxlength
    255Maximum input size; sets the HTML input tag's maxlength attribute.
    dollars_and_centsbooleanFalseIn view mode, shows dollars and cents. Enter "123.123" and "$123.12" is shown. (Note: this feature is not localized; it always uses the dollar sign, period, and two digits precision.)
    size
    5Size of the input field; sets the HTML input tag's size attribute.

     

    FileWidget

    Renders an HTML widget so a user can upload a file.

    filewidget.png

     

    ImageWidget

    Renders an HTML widget that can be used to upload, display, delete, and replace images. You can provide a display_threshold that allows you to set the size of an image; if it's below this size, the image will display in the Web page.

    imagewidget.png

     

    Special Properties

    NameTypeDefaultDescription
    display_thresholdinteger102400Only display the image inline if img.getSize() <= display_threshold

     

    InAndOutWidget

    In edit mode, renders a widget for moving items from one list to another. Items are removed from the source list. This can be used to choose multiple values from a list. This provides a good alternative to the MultiSelectionWidget when the vocabulary is too long for checkboxes.

    inandoutwidget.png

     

    Special Properties

     

    IntegerWidget

    A simple HTML input box for a string.

    Special Properties

    NameTypeDefaultDescription
    size
    6Size of the select widget; sets the HTML select tag's size attribute.
    NameTypeDefaultDescription
    maxlength
    255Maximum input size; sets the HTML input tag's maxlength attribute
    size
    5Size of the input field; sets the HTML input tag's size attribute.

     

    KeywordWidget

    This widget allows the user to select keywords or categories from a list. It is used for the Categories field in the Categorization Schema (Plone 3+) or the equivalent Keywords field on the Properties Tab (Plone < 3) of a content object.
    Keywords are drawn from the field vocabulary and/or the unique values for the field in a specified catalog.
    Additional keywords may be added unless the enforceVocabulary property of the field is True.

    Special Properties

    NameTypeDefaultDescription
    vocab_source
    portal_catalogSets the catalog to search for additional vocabulary to be combined with the vocabulary defined for the field. Additional keywords from existing content are found using catalog.uniqueValuesFor(fieldName).
    roleBasedAdd
    TrueOnly shows the "New keywords" input for adding keywords if the current user has one of the roles stored in the allowRolesToAddKeywords property in the site_properties property sheet in portal_properties

     

    LabelWidget

    Used to display labels on forms -- without values or form input elements.

     

    LinesWidget

    Displays a text area so that users can enter a list of values, one per line.

    lineswidget.png

     

    Special Properties

    NameTypeDefaultDescription
    rowsinteger 5Rows of the lines widget; sets the HTML textarea tag's rows attribute.
    colsinteger 40Columns of the lines widget; sets the HTML textarea tag's cols attribute.

     

    MultiSelectionWidget

    A selection widget; by default it's an HTML select widget which can be used to choose multiple values. As a checkbox users can choose one or more values from a list (useful if the list is short).

    multiselectionwidget-listbox.png

     

    multiselectionwidget-checkbox.png

     

    Special Properties

    NameTypeDefaultDescription
    formatstringselectPossible values: 'select' or 'checkbox'. Uses a either a series of checkboxes or a multi-selection list. Note that checkboxes have much better usability for short vocabularies. Consider using the InAndOutWidget for longer vocabularies.
    size
    5Defines the size of the multi-select list. Does not apply for checkboxes.

     

    PasswordWidget

    Renders an HTML password input.

    Special Properties

    NameTypeDefaultDescription
    maxlength
    255Maximum input size; sets the HTML input tag's maxlength attribute.
    size
    20Size of the input field; sets the HTML input tag's size attribute.

    Standard Properties

    NameTypeDefault
    populatebooleanFalse
    postbackbooleanFalse
    modes
    ('edit',)

     

    PicklistWidget

    Similar to the InAndOutWidget, but the values stay in the source list after selection.

    picklistwidget.png

     

    Special Properties

    NameTypeDefaultDescription
    sizeinteger6Size of the selection box; sets the HTML select tag's size attribute.

     

    ReferenceWidget

    Renders an HTML text input box which accepts a list of possible reference values. Used in combination with the Reference Field.
    Note: In Plone 2.5 and above, the ReferenceBrowserWidget is a usually a better choice for a reference widget due to its ability to browse for content referenceable objects.

    referencewidget.png

     

    Special Properties

    NameTypeDefaultDescription
    checkbox_bound
    5When the number of items exceeds this value, multi-selection lists are used. Otherwise, radio buttons or checkboxes are used.
    destination
    NoneMay be:
    • ".", context object;
    • None, any place where Field.allowed_types can be added;
    • string path;
    • name of method on instance (it can be a combination list);
    • a list, combining all item above;
    • a dict, where {portal_type:} destination is relative to portal root
    addable
    FalseCreate createObject link for every addable type
    destination_types
    NoneEither a single type given as a string, or a list of types given as a string, defining what types we allow adding to. Only applies when addable is set on the widget.

     

    ReferenceBrowserWidget

    A sophisticated widget for browsing, adding and deleting references.
    Standard in Plone 2.5+, available for earlier versions as an add-on product.
    Import from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget.

    Special Properties

    NameTypeDefaultDescription
    sizeinteger
    Size of the field if not multiValued; sets the HTML input tag's size attribute.
    default_search_indexstringSearchableTextwhen a user searches in the popup, this index is used by default
    show_indexesbooleanFalse If True, a drop-down list is shown in the popup to select the index used for searching. If set to False, default_search_index will be used.
    available_indexesdict{} Optional dictionary containing all the indexes that can be used for searching along with their friendly names. Format: {'catalogindex':'Friendly Name of Index', ... } The friendly names are shown in the widget.
    Caution: If you set show_indexes True, but do not use this property to specify indexes, then all the indexes will be shown.
    allow_searchbooleanTrue If True, a search form is included in the popup.
    allow_browseTrueAllows the user to browse content to find referenceable content.
    startup_directorystring'' Directory shown when the popup opens. Optional. When empty, the current folder is used. See the ATReferenceBrowser readme.txt for advanced usage.
    base_querydict or name of method
    Defines query terms that will apply to all searches, mainly useful to create specific restrictions when allow_browse=0. Can be either a dictonary with query parameters, or the name of a method or callable available in cotext that will return such a dictionary.
    force_close_on_insertbooleanFalse If true, closes the popup when the user choses insert. This overrides the default behavior in multiselect mode.
    search_catalogstring'portal_catalog'Specifies the catalog used for searches
    allow_sortingbooleanFalse Allows changing the order of referenced objects (requires multiValued).
    show_review_statebooleanFalse If True, popup will display the workflow state for objects.
    show_pathbooleanFalse If True, display the relative path (relative to the portal object) of referenced objects.
    only_for_review_states
    None If set, content items are only referenceable if their workflow state matches one of the specified states. If None there will be no filtering by workflow state.
    image_portal_typessequence() Use to specify a list of image portal_types. Instances of these portal types are previewed within the popup widget
    image_methodstringNone Specifies the name of a method that is added to the image URL to preview the image in a particular resolution (e.g. 'mini' for thumbnails).
    history_lengthinteger0 If not zero, enables a history feature that show the paths of the last N visited folders.
    restrict_browsing_to_startup_directorybooleanFalse If True, the user will not be able to browse above the starting directory.

     

    RichWidget

    Allows the input of text, or upload of a file, in multiple formats that are then transformed as necessary for display. For example, allows you to type some content, choose formatting and/or upload a file. If available, the visual editor set in personal preferences is used for editing and formatting.

    richwidget.png

     

    Special Properties

    NameTypeDefaultDescription
    rowsinteger5Number of rows. (Since the visual mode of the RichWidget is controlled by JavaScript, this is not very useful.)
    colsinteger40Number of columns. (Since the visual mode of the RichWidget is controlled by JavaScript, this is not very useful.)
    allow_file_uploadbooleanTrueIf True, a file upload option is included with the field.

     

    SelectionWidget

    Renders an HTML selection widget, which can be represented as a dropdown, or as a group of radio buttons.

    selectionwidget-dropdown.png

     

    selectionwidget-radio.png

     

    Special Properties

    NameTypeDefaultDescription
    formatstring'flex'Possible values: 'flex', 'select', 'radio'. Uses radio buttons when set to radio, and a single-selection list when set to select. Using flex will automatically use single-selection lists for more than three settings at a time, and a single-select list for up to three settings.

     

    StringWidget

    Renders an HTML text input box which accepts a single line of text. For simple text lines such as author.

    stringwidget.png

     

    Special Properties
    NameTypeDefaultDescription
    maxlengthinteger255Maximum input length in characters; sets the HTML input tag's maxlength attribute.
    size
    30Size of the input widget; sets the HTML input tag's size attribute.

     

    TextAreaWidget

    Renders an HTML text area for typing a few lines of text. Also provides for the entry of the content in multiple formats when allowed_content_types in the enclosing TextField allows it.

    textareawidget.png

     

    Special Properties

    NameTypeDefaultDescription
    rowsinteger 5Number of rows for the edit widget; sets the HTML textarea tag's rows attribute.
    colsinteger 40Column width of the edit widget; sets the HTML textarea tag's cols attribute.
    append_onlyboolean FalseSet this attribute to True to make an append-only TextArea widget. New text gets added to the top of the existing text, dividing the new text from the existing text using the divider property. The existing text is shown below the TextArea, and is not editable. This currently works with TextArea widgets and using plain text format.
    dividerstring========================Divider text marker to use for append only text areas. Only used then the append_only property is True.
    maxlengthintegerFalse If non-zero, sets a maximum input length in characters. Since the HTML textarea tag has no maxlength property, this is enforced via a JavaScript snippet. So, it is is not applicable when JavaScript is unavailable.

    Add-on Widgets

    To find all available add-on widgets contributed by the community, follow this link.

    4.3. Validator Reference

    A quick reference to the built-in Archetypes validators.

    Using Validators

    Archetypes fields may have validators specified in the Field schema. For example, the schema for the basic page type includes the stanza:

    ATDocumentSchema = ATContentTypeSchema.copy() + Schema((
        TextField('text',
    ...
                  validators = ('isTidyHtmlWithCleanup',),
    ...
        ),
    

    This specifies that the isTidyHtmlWithCleanup test will be applied to validate form input.

    You may specify a sequence of validators:

    validators = ('isMaxSize', 'isTidyHtmlWithCleanup',),
    

    and the validators will tested in order.

    The validators sequence may contain two kinds of entries:

    • The string names of validators registered with the validation service (see Products.validation);
    • Instances of classes implementing the IValidator interface (Products.validation.interfaces.IValidator.IValidator).

    A validation specification using a validator class instance can look like:

    validators = ( ExpressionValidator('python: int(value) == 5'), )
    

     

    Registered Validators

    These are validators pre-registered with the validation service. They may be specified by name.

    NameUseDetails
    isDecimalIs the input a decimal number.Allows exponent notation.
    isIntIs the input an integer.
    isPrintableDoes not contain unprintable charactersr'[a-zA-Z0-9\s]+$'
    isSSNIs a well-formed social-security numberVery naive: r'^\d{9}$'
    isUSPhoneNumberIs a valid US phone numberLooks for 10 digits, ignores spaces, parens and dashes
    isInternationalPhoneNumberIs a valid international phone numberLooks for any number of digits, ignores spaces, parens and dashes
    isZipCodeVery naive: is five or nine digits
    isURLIs a valid URLRecognizes most protocols
    isEmailIs a valid e-mail addressA pretty good regular expression test
    isMailToIs an e-mail address preceded by "mailto:"
    isUnixLikeNamePasses the basic test to be a Unix-style namer"^[A-Za-z][\w\d\-\_]{0,7}$"
    isMaxSizeTests if an upload, file or something supporting len() is smaller than a given max size value.Tests against a maxsize attribute on the field
    isValidDateTests whether or not input value can be converted to a DateTime object. 
    isEmptyInput value must be empty. 
    isEmptyNoErrorInput value must be empty.Validation will fail if input value is not empty; but no error will show.
    isValidIdInput value is a valid identifier. 
    isTidyHtmlUses mx.Tidy to validate HTML input. Fails on errors and warnings. 
    isTidyHtmlWithCleanupUses mx.Tidy to validate HTML input. Fails only on errors; cleans up. 
    isNonEmptyFileThe uploaded file is not empty. 
    isTALValidates as Template Attribute Language 

     

    Useful Validation Classes

    These classes are useful for creating your own validation class instances. Imports and prototypes are shown. See source for details.

    ExpressionValidator

    Evaluates an expression to test the input value.

    from Products.validation.validators.ExpressionValidator import ExpressionValidator
    
    def ExpressionValidator(expression=None, errormsg=None)
    

    RegexValidator

    Tests value against a regular expression after removing ignore

    characters.

    from Products.validation.validators.RegexValidator import RegexValidator
    
    def RegexValidator(name, regex, title=name, description='',
     errmsg='fails tests of %s' % name, ignore=None)
    

    RangeValidator

    Tests to see if specified minval <= input_value < maxval

    from Products.validation.validators.RangeValidator import RangeValidator
    
    def RangeValidator(name, minval=0.0, maxval=0.0, title='', description='')