Behaviors
Contents
24. Behaviors#
In this part you will:
Add another field to talks by using a behavior
Add a custom index for the field
Add a metadata column for the field
Topics covered:
Behaviors
Indexes
Metacolumns
You can extend the functionality of your Dexterity object by writing an adapter that adapts your dexterity object to add another feature or aspect.
But if you want to use this adapter, you must somehow know that an object implements that. Also, adding more fields to an object would not be easy with such an approach.
24.1. Dexterity Approach#
Dexterity has a solution for it, with special adapters that are called and registered by the name behavior.
A behavior can be added to any content type through the web and at runtime.
All default views (e.g. the add- and edit-forms) know about the concept of behaviors. When rendering forms, the views also check whether there are behaviors referenced with the current context and if these behaviors have a schema of their own, these fields get shown in addition.
24.2. Names and Theory#
The name behavior is not a standard term in software development. But it is a good idea to think of a behavior as an aspect. You are adding an aspect to your content type and you want to write your aspect in such a way that it works independently of the content type on which the aspect is applied. You should not have dependencies to specific fields of your object or to other behaviors.
Such an object allows you to apply the open/closed principle to your dexterity objects.
24.3. Practical example#
Note
You can also use the Plone Command Line Tool plonecli
to initially create a behavior and edit it afterwards
So, let us write our own small behavior.
We want some talks, news items or other content to be represented on the frontpage similar to what we did with the "hot news" field early on.
So for now, our behavior just adds a new field to store this information.
We want to keep a clean structure, so we create a behaviors
directory first, and include it into the zcml declarations of our configure.zcml
.
<include package=".behaviors" />
Then, we add an empty behaviors/__init__.py
and a behaviors/configure.zcml
containing
1<configure
2 xmlns="http://namespaces.zope.org/zope"
3 xmlns:plone="http://namespaces.plone.org/plone"
4 i18n_domain="ploneconf.site">
5
6 <plone:behavior
7 title="Featured"
8 name="ploneconf.featured"
9 description="Control if a item is shown on the frontpage"
10 provides=".featured.IFeatured"
11 />
12
13</configure>
And a behaviors/featured.py
containing:
1from plone.autoform.interfaces import IFormFieldProvider
2from plone.supermodel import model
3from zope import schema
4from zope.interface import provider
5
6@provider(IFormFieldProvider)
7class IFeatured(model.Schema):
8
9 featured = schema.Bool(
10 title='Show this item on the frontpage',
11 required=False,
12 )
This is exactly the same type of schema as the one in the talk content-type.
The only addition is @provider(IFormFieldProvider)
that makes sure that the fields in the schema are displayed in the add- and edit-forms.
Let's go through this step by step.
We register a behavior in behaviors/configure.zcml. We do not say for which content type this behavior is valid. You do this through the web or in the GenericSetup profile.
We create a interface in behaviors/featured.py for our behavior. We make it also a schema containing the fields we want to declare. We could just define schema fields on a zope.interface class, but we use an extended form from
plone.supermodel
, else we could not use the fieldset features.We mark our schema as a class that also provides the
IFormFieldProvider
interface using a decorator. The schema class itself provides the interface, not its instance!We also add a
fieldset
so that our fields are not mixed with the normal fields of the object.We add a normal Bool schema field to control if a item should be displayed on the frontpage.
Note
It can be a bit confusing when to use factories or marker interfaces and when not to.
If you do not define a factory, your attributes will be stored directly on the object. This can result in clashes with other behaviors.
You can avoid this by using the plone.behavior.AnnotationStorage
factory.
This stores your attributes in an Annotation.
But then you must use a marker interface if you want to have custom viewlets, browser views or portlets.
Without it, you would have no interface against which you could register your views.
24.4. Adding it to our talk#
We could add this behavior now via the plone control panel. But instead, we will do it directly and properly in our GenericSetup profile
We must add the behavior to profiles/default/types/talk.xml
:
1<?xml version="1.0"?>
2<object name="talk" meta_type="Dexterity FTI" i18n:domain="plone"
3 xmlns:i18n="http://xml.zope.org/namespaces/i18n">
4 ...
5 <property name="behaviors">
6 <element value="plone.dublincore"/>
7 <element value="plone.namefromtitle"/>
8 <element value="ploneconf.featured"/>
9 </property>
10 ...
11</object>
After a restart and the reinstallation of the product we now have the new field we added through the behavior:

24.5. Add a index for the new field#
To use these new information for example in searches or listings we have to add an index to the plone_catalog
for it. Indexing is the action to make object data search-able. Plone stores available indexes in the database.
Note
You can create them through-the-web and inspect existing indexes in portal_catalog on Index tab. To have those indexes directly after the installation you have to add those indexes like we will show in this chapter.
First of all we have to decide which kind of Index we need to add for our new field. Often used index types are for example:
FieldIndex stores values as is
BooleanIndex stores boolean values as is
KeywordIndex allows keyword-style look-ups (query term is matched against all the values of a stored list)
DateIndex and DateRangeIndex store dates (Zope 2 DateTime objects) in searchable format. The latter provides ranged searches.
Therefore we have a boolean field for the featured information it would be obvious to use the BooleanIndex for this.
To add a new index we have to change the catalog.xml
in the profiles/default
folder of our product. Without changes the file should look like this:
1<?xml version="1.0"?>
2<object name="portal_catalog">
3 <!--<column value="my_meta_column"/>-->
4</object>
To add the new BooleanIndex to the file we have to change the file as following:
1<?xml version="1.0"?>
2<object name="portal_catalog">
3 <index name="featured" meta_type="BooleanIndex">
4 <indexed_attr value="featured"/>
5 </index>
6</object>
To understand this snippet we have to understand the tags and information we are using:
The
index
-tag will tell theplone_catalog
that we want to add a new indexname
will be shown in the overview ofportal_catalog
and can be used in listings and searches later onmeta_type
will determine the kind of index we want to useThe
indexed_attr
will include the fieldname of the information we are going to save in the index
After a restart and reinstallation of the product, it should now create a new index in the portal_catalog
.
Note
Instead of deinstall/install in the Add-Ons
controlpanel, we can import new or altered XML files in the ZMI
. To do so go to portal_setup
, switch to the Import
-Tab and search for the profile to import like in this case: ploneconf.site
.
To see if the adding was successfully we will open the ZMI of our plone-site and navigate to the portal_catalog
and click the Indexes
-Tab. In the above list the new index featured
should pop up.
24.6. Add a metadata column for the new field#
The same rules and methods shown above for indexes apply for metadata columns. The difference with metadata is that it is not used for searching the catalog if Plone, Metadata is used for displaying the search results returned from the catalog.
To add a metadata column for featured we have to add one more line in the catalog.xml
like this:
1<?xml version="1.0"?>
2<object name="portal_catalog">
3 <index name="featured" meta_type="BooleanIndex">
4 <indexed_attr value="featured"/>
5 </index>
6 <column value="featured"/>
7</object>
After another restart and another import of the xml-profile the new metadata column can be found in the portal_catalog
in your ZMI
under the tab Metadata
.
24.7. Exercises#
Since you now know how to add indexes to the portal_catalog
it is time for some exercise.
24.7.1. Exercise 1#
Add a new index for the speaker
-field of our content type Talk
Solution
1<?xml version="1.0"?>
2<object name="portal_catalog">
3 <index name="featured" meta_type="BooleanIndex">
4 <indexed_attr value="featured"/>
5 </index>
6 <index name="speaker" meta_type="FieldIndex">
7 <indexed_attr value="speaker"/>
8 </index>
9</object>