13. Dexterity I: "Through The Web" – Mastering Plone 5 development

13. Dexterity I: "Through The Web"#

In this part you will:

  • Create a new content type called Talk.

Topics covered:

  • Content types

  • Archetypes and Dexterity

  • Fields

  • Widgets

13.1. What is a content type?#

A content type is a kind of object that can store information and is editable by users. We have different content types to reflect the different kinds of information about which we need to collect and display information. Pages, folders, events, news items, files (binary) and images are all content types.

It is common in developing a web site that you'll need customized versions of common content types, or perhaps even entirely new types.

Remember the requirements for our project? We wanted to be able to solicit and edit conference talks. We could use the Page content type for that purpose. But we need to make sure we collect certain bits of information about a talk and we couldn't be sure to get that information if we just asked potential presenters to create a page. Also, we'll want to be able to display talks featuring that special information, and we'll want to be able to show collections of talks. A custom content type will be ideal.

13.2. The makings of a Plone content type#

Every Plone content type has the following parts:

Schema

A definition of fields that comprise a content type; properties of an object.

FTI

The "Factory Type Information" configures the content type in Plone, assigns it a name, additional features and available views to it.

Views

A view is a representation of the object and the content of its fields that may be rendered in response to a request. You may have one or more views for an object. Some may be visual — intended for display as web pages — others may be intended to satisfy AJAX requests and render content in formats like JSON or XML.

13.3. Dexterity and Archetypes - A Comparison#

There used to be two content frameworks in Plone:

  • Dexterity: new and default.

  • Archetypes: the old default in Plone 4 and deprecated. Still used in some add-ons.

  • Plone 4.x: Archetypes is the default, with Dexterity available.

  • Plone 5.x: Dexterity is the default, with Archetypes available. In Plone 6 Archetypes will not be available any more.

  • For both, add and edit forms are created automatically from a schema.

What are the differences?

  • Dexterity: New, faster, modular, no dark magic for getters and setters.

  • Archetypes had magic setter/getter - use talk.getAudience() for the field audience.

  • Dexterity: fields are attributes: talk.audience instead of talk.getAudience().

"Through The Web" or TTW, i.e. in the browser, without programming:

  • Dexterity has a good TTW story.

  • Archetypes has no TTW story.

  • UML-modeling: ArchGenXML for Archetypes, agx for Dexterity

Approaches for Developers:

  • Schema in Dexterity: TTW, XML, Python. Interface = schema, often no class needed.

  • Schema in Archetypes: Schema only in Python.

  • Dexterity: Easy permissions per field, easy custom forms.

  • Archetypes: Permissions per field are hard, custom forms even harder.

  • If you have to program for old Plone 4-based sites you still need to know Archetypes!

  • If starting fresh always use Dexterity.

Extending:

  • Dexterity has Behaviors: easily extendable. Just activate a behavior TTW and your content type is e.g. translatable (plone.app.multilingual).

  • Archetypes has archetypes.schemaextender. Powerful but not as flexible.

We have only used Dexterity for the last few years. We teach Dexterity and not Archetypes because it's more accessible to beginners, has a great TTW story and is the future.

Views:

  • Both Dexterity and Archetypes have a default view for content types.

  • Browser Views provide custom views.

  • You can generate views for content types in the browser without programming (using the plone.app.mosaic Add-on).

  • Display Forms.

13.4. Modifying existing types#

  • Go to the control panel http://localhost:8080/Plone/@@dexterity-types

  • Inspect some of the existing default types.

  • Select the type News Item and add a new field Hot News of type Yes/No

  • In another tab, add a News Item and you'll see the new field.

  • Go back to the schema-editor and click on Edit XML Field Model.

  • Note that the only field in the XML schema of the News Item is the one we just added. All others are provided by behaviors.

  • Edit the form-widget-type so it says:

    <form:widget type="z3c.form.browser.checkbox.SingleCheckBoxFieldWidget"/>
    
  • Edit the News Item again. The widget changed from a radio field to a check box.

  • The new field Hot News is not displayed when rendering the News Item. We'll take care of this later.

13.5. Creating content types TTW#

In this step we will create a content type called Talk and try it out. When it's ready we will move the code from the web to the file system and into our own add-on. Later we will extend that type, add behaviors and a viewlet for Talks.

  • Add new content type "Talk" and some fields for it:

    • Add new field "Type of talk", type "Choice". Add options: talk, keynote, training.

    • Add new field "Details", type "Rich Text" with a maximal length of 2000.

    • Add new field "Audience", type "Multiple Choice". Add options: beginner, advanced, pro.

    • Check the behaviors that are enabled: Dublin Core metadata, Name from title. Do we need them all?

  • Test the content type.

  • Return to the control panel http://localhost:8080/Plone/@@dexterity-types

  • Extend the new type: add the following fields:

    • "Speaker", type: "Text line"

    • "Email", type: "Email"

    • "Image", type: "Image", not required

    • "Speaker Biography", type: "Rich Text"

  • Test again.

Here is the complete XML schema created by our actions:

 1<model xmlns:lingua="http://namespaces.plone.org/supermodel/lingua"
 2     xmlns:users="http://namespaces.plone.org/supermodel/users"
 3     xmlns:security="http://namespaces.plone.org/supermodel/security"
 4     xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
 5     xmlns:form="http://namespaces.plone.org/supermodel/form"
 6     xmlns="http://namespaces.plone.org/supermodel/schema">
 7  <schema>
 8    <field name="type_of_talk" type="zope.schema.Choice">
 9      <description/>
10      <title>Type of talk</title>
11      <values>
12        <element>Talk</element>
13        <element>Training</element>
14        <element>Keynote</element>
15      </values>
16    </field>
17    <field name="details" type="plone.app.textfield.RichText">
18      <description>Add a short description of the talk (max. 2000 characters)</description>
19      <max_length>2000</max_length>
20      <title>Details</title>
21    </field>
22    <field name="audience" type="zope.schema.Set">
23      <description/>
24      <title>Audience</title>
25      <value_type type="zope.schema.Choice">
26        <values>
27          <element>Beginner</element>
28          <element>Advanced</element>
29          <element>Professionals</element>
30        </values>
31      </value_type>
32    </field>
33    <field name="speaker" type="zope.schema.TextLine">
34      <description>Name (or names) of the speaker</description>
35      <title>Speaker</title>
36    </field>
37    <field name="email" type="plone.schema.email.Email">
38      <description>Adress of the speaker</description>
39      <title>Email</title>
40    </field>
41    <field name="image" type="plone.namedfile.field.NamedBlobImage">
42      <description/>
43      <required>False</required>
44      <title>Image</title>
45    </field>
46    <field name="speaker_biography" type="plone.app.textfield.RichText">
47      <description/>
48      <max_length>1000</max_length>
49      <required>False</required>
50      <title>Speaker Biography</title>
51    </field>
52  </schema>
53</model>

13.6. Moving contenttypes into code#

It's awesome that we can do so much through the web. But it's also a dead end if we want to reuse this content type in other sites.

Also, for professional development, we want to be able to use version control for our work, and we'll want to be able to add the kind of business logic that will require programming.

So, we'll ultimately want to move our new content type into a Python package. We're missing some skills to do that, and we'll cover those in the next couple of chapters.

13.7. Exercises#

13.7.1. Exercise 1#

Modify Pages to allow uploading an image as decoration (like News Items do).

Solution

The images are displayed above the title.

13.7.2. Exercise 2#

Create a new content type called Speaker and export the schema to a XML File. It should contain the following fields:

  • Title, type: "Text Line"

  • Email, type: "Email"

  • Homepage, type: "URL" (optional)

  • Biography, type: "Rich Text" (optional)

  • Company, type: "Text Line" (optional)

  • Twitter Handle, type: "Text Line" (optional)

  • IRC Handle, type: "Text Line" (optional)

  • Image, type: "Image" (optional)

Do not use the DublinCore or the Basic behavior since a speaker should not have a description (unselect it in the Behaviors tab).

We could use this content type later to convert speakers into Plone users. We could then link them to their talks.

Solution

The schema should look like this:

<model xmlns:lingua="http://namespaces.plone.org/supermodel/lingua"
       xmlns:users="http://namespaces.plone.org/supermodel/users"
       xmlns:security="http://namespaces.plone.org/supermodel/security"
       xmlns:marshal="http://namespaces.plone.org/supermodel/marshal"
       xmlns:form="http://namespaces.plone.org/supermodel/form"
       xmlns="http://namespaces.plone.org/supermodel/schema">
  <schema>
    <field name="title" type="zope.schema.TextLine">
      <title>Name</title>
    </field>
    <field name="email" type="plone.schema.email.Email">
      <title>Email</title>
    </field>
    <field name="homepage" type="zope.schema.URI">
      <required>False</required>
      <title>Homepage</title>
    </field>
    <field name="biography" type="plone.app.textfield.RichText">
      <required>False</required>
      <title>Biography</title>
    </field>
    <field name="company" type="zope.schema.TextLine">
      <required>False</required>
      <title>Company</title>
    </field>
    <field name="twitter_handle" type="zope.schema.TextLine">
      <required>False</required>
      <title>Twitter Handle</title>
    </field>
    <field name="irc_name" type="zope.schema.TextLine">
      <required>False</required>
      <title>IRC Handle</title>
    </field>
    <field name="image" type="plone.namedfile.field.NamedBlobImage">
      <required>False</required>
      <title>Image</title>
    </field>
  </schema>
</model>