Upload
david-glick
View
5.014
Download
0
Tags:
Embed Size (px)
DESCRIPTION
This talk covers the basics of building content types with Dexterity, and how it compares to doing so with Archetypes; what sorts of tasks Dexterity is best suited for, and which ones it isn't ready for yet * an update on the most recent improvements to Dexterity
Citation preview
A Dexterity Intro for Recovering Archetypes Addicts
David GlickPlone Symposium East, 2010
What is a content type?
ZODB stores objects
Content type (or portal_type)categorizes objects
Page Something Else
Schema
(what sort of data can be stored)
Workflow
(who can do things when)
Custom view templates
(what it looks like)
Miscellaneous settings
• Placeful restrictions• Comments• Searchability• Per-type portlet assignments• etc.
History Lesson
http://commons.wikimedia.org/wiki/File:1893_Nina_Pinta_Santa_Maria_replicas.jpg
Content Management Framework (CMF)• Underlying framework for registering
types, assigning workflow• CMFDefault contains sample types which
used to be used by Plone• Not schema-based
Archetypes
• Schema-based form generation• Basis of Plone's current default content
types (ATContentTypes)• Not going away anytime soon
Dexterity
Martin Aspeli
Goals
http://www.fickr.com/photos/paul-w-locke/1662634481/sizes/m/
Make filesystem content type development sane
Make through-the-web content type development possible
Make it possible to switch back and forth between the 2
Philosophy
http://www.fickr.com/photos/ulrichsson/3519217737/
Reuse over reinvention
Produc ts .Arc he type s
Small over big
felds
widgets
base classes
storage
metadataschema
referenceengine
plone .de x te rity
plone.app.dexterity
plone.schemaeditor
z3c.form
plone.behavior
plone.app.relations
plone.directives.*
plone.autoform
plone.supermodel
Natural interaction over excessive generality
understanding
time
Real code over generated code
Zope 3 over Zope 2
Automated testing over wishful thinking
Example: Photo Gallery(example.dexgallery in the collective)
• Photo Gallery content type• Photo content type
• Tagging• Geolocation
Rapid Development
Archetypes• ArchGenXML
• ZopeSkel
Dexterity• collective.dexteritypaste
• Though-the-webcontent type creation
$ bin/zopeskel dexterity
TTW type development
Exporting a type
• GenericSetup export for now;better UI coming :)
Base class
Archetypes• BaseObject, usually via
ATContentTypes
• many mixins
• typically need a custom subclass
Dexterity• plone.dexterity.content.Item or
plone.dexterity.content.Container
• fewer mixins
• custom subclasses typically unneeded
Schemas
Archetypes• unique schema format
• define a schema, assign it to the content class's 'schema' attribute
Dexterity• Zope 3 schemas
• Can also be represented in a unique XML schema format
• Associated with a content type via the FTI in portal_types
Filesystem roundtripping
Web File s y s tem
Zope 3 Schema
XML schema in FTI
ContentEditing
SchemaEditing
xmlxml
XML schemaon flesystem
py
Schema asPython interface
GenericSetupimport/export
Externaltools
PhotoSchema = atapi.Schema(( # (fields here)))
schemata.finalizeATCTSchema(PhotoSchema, moveDiscussion=False)
class Photo(base.ATCTContent): implements(IPhoto) meta_type = "Photo" schema = PhotoSchema
class IPhoto(form.Schema): # (fields here)
<property name="schema">example.dexgallery.dexterity.content.photo.IPhoto</property>
From profles/default/types/photo.xml:
From content/photo.py:From content/photo.py:
Schemas
Archetypes Dexterity
Accessing fields
Archetypes• obj.getField('fieldname')\
.get(obj)
• obj.getFieldname()
(magically generated accessor on the content class)
Dexterity• obj.fieldname
(values are simply stored as attributes)
• Use property descriptors if you need custom accessor/mutator logic
• __getattr__ makes sure to get default value from schema if there's no attribute stored yet
Field security
Archetypes• Read/write permissions
can be specified per field in the schema
Dexterity• Read/write permissions
can be specified per field in the schema
• Controlled access (from RestrictedPython)
• Implemented using __allow_access_to_unprotected_subobjects__
atapi.TextField('caption', required = False, searchable = True, storage = atapi.AnnotationStorage(migrate=True), validators = ('isTidyHtmlWithCleanup',), default_content_type = 'text/html', default_output_type = 'text/x-html-safe', widget = atapi.RichWidget( label = _(u'Caption'), ), ),
from plone.app.textfield import RichText caption = RichText( title = _(u'Caption'), required = False, )
From content/photo.py:From content/photo.py:
Caption field (rich text)
Archetypes Dexterity
from plone.app.blob.field import ImageField
ImageField('image', required = True, storage = atapi.AnnotationStorage(migrate=True), languageIndependent = True, swallowResizeExceptions = zconf.swallowImageResizeExceptions.enable, pil_quality = zconf.pil_config.quality, pil_resize_algo = zconf.pil_config.resize_algo, max_size = zconf.ATNewsItem.max_image_dimension, validators = (('isNonEmptyFile', V_REQUIRED), ('checkNewsImageMaxSize', V_REQUIRED)), widget = atapi.ImageWidget( label = _(u'Photo'), show_content_type = False ), ),
from plone.namedfile.field import NamedBlobImage
image = NamedBlobImage( title = _(u'Photo'), )
Photo field (image)Archetypes
Dexterity
Image scaling
• Now supports arbitrary sizes, e.g.
• (supported for both Archetypes and Dexterity in Plone 4)
<img tal:defne="scale photo_obj/@ @ images" tal:replace="structure python:scale.scale('image', width=1200, height=300, direction='keep').tag()"/>
atapi.ReferenceField( 'tags', storage=atapi.AnnotationStorage(), widget=atapi.ReferenceWidget( label=_(u"Tags"), ), required=False, relationship='photo_tag', allowed_types=('Document',), multiValued=True, ),
from z3c.relationfield.schema import \ RelationList, RelationChoicetags = RelationList( title = _(u'Tags'), default = [], value_type=RelationChoice( title = _(u'Tag'), source = ObjPathSourceBinder( navigation_tree_query = {'path': {'query':'/'}}, portal_type = 'Document', ), ), required = False, )
From content/photo.py:From content/photo.py:
Tags field (relations)
Archetypes Dexterity
Content tree widget
Indexing fields
• similar for both• for Dexterity you may need to implement
your own SearchableText indexer, e.g.
from plone.indexer import indexer
@indexer(IPhoto)def SearchableText(obj): return ' '.join([obj.Title(), obj.Description(), obj.caption.output])
Custom views
Archetypes
• default: base_view.cpt
• add a skin layer template or browser view, register in the FTI
Dexterity
• default: view class in plone.dexterity.browser.view
• add a skin layer template or browser view, register in the FTI
Grok-style configuration
• Configuration via directives inline with code, instead of via ZCML declarations. e.g.
• Supported but not required
from five import grokclass View(grok.View): grok.context(IPhoto) grok.require('zope2.View')
Custom forms
Archetypes
• difficult
Dexterity
• full power of z3c.form
(write custom forms that reference fields from the type's schema)
• or, use grok directives on the schema to influence how fields appear in all forms (e.g., custom widget, etc.)
Adding items
Archetypes• Autogenerated factory
method
• In Plone, portal_factory prevents premature creation and indexing
Dexterity• z3c.form add form
• Default works in many cases, but can be replaced by setting add_view_expr in the FTI
• No content is constructed until the form is submitted
Extending content types
Archetypes• archetypes.schemaextender
• “schema extender” adapters can provide additional fields
• “schema modifier” adapters can make arbitrary changes to a schema
Dexterity• “behaviors”
• can provide additional fields
• can mark the content item with a particular interface
• can be turned on/off through the web for each content type
Behaviors
ATFile
schema
CustomATFile
s ubc la s s ing
ATFile
schema
behav iors
DexterityFile
model
thumbnailimage
name fromtitle
ratingsgeolocatable
versioned
s c hemae x te ns ion
ATFile
schema
schemaschema
schema Decolayout
Geolocation behavior
Geolocation behavior
• Adds a geolocation field• Provides an adapter to store the value of
that field in an annotation• Marks the item with IGeolocatableMarker• Some adapters so that Products.Maps
knows how to get a geolocation from an item with IGeolocatableMarker
Registering a type
Archetypes• registerType() after class
definition magically generates Zope 2-style factory methods
• boilerplate in __init__.py finds types and completes registration
• type configuration in GenericSetup profile references the factory method
Dexterity• Just GenericSetup
(profiles/default/types/[Type_Id].xml)
"""Main product initializer"""
from zope.i18nmessageid import MessageFactoryfrom example.dexgallery.archetypes import config
from Products.Archetypes import atapifrom Products.CMFCore import utils
# Define a message factory for when this product is internationalised.# This will be imported with the special name "_" in most modules. Strings# like _(u"message") will then be extracted by i18n tools for translation.
archetypesMessageFactory = MessageFactory('example.dexgallery.archetypes')
def initialize(context): """Initializer called when used as a Zope 2 product.
This is referenced from configure.zcml. Regstrations as a "Zope 2 product" is necessary for GenericSetup profiles to work, for example.
Here, we call the Archetypes machinery to register our content types with Zope and the CMF. """
# Retrieve the content types that have been registered with Archetypes # This happens when the content type is imported and the registerType() # call in the content type's module is invoked. Actually, this happens # during ZCML processing, but we do it here again to be explicit. Of # course, even if we import the module several times, it is only run # once.
content_types, constructors, ftis = atapi.process_types( atapi.listTypes(config.PROJECTNAME), config.PROJECTNAME)
# Now initialize all these content types. The initialization process takes # care of registering low-level Zope 2 factories, including the relevant # add-permission. These are listed in config.py. We use different # permissions for each content type to allow maximum flexibility of who # can add which content types, where. The roles are set up in rolemap.xml # in the GenericSetup profile.
for atype, constructor in zip(content_types, constructors): utils.ContentInit('%s: %s' % (config.PROJECTNAME, atype.portal_type), content_types=(atype, ), permission=config.ADD_PERMISSIONS[atype.portal_type], extra_constructors=(constructor,), ).initialize(context)
from zope.i18nmessageid import MessageFactory
_ = MessageFactory('example.dexgallery')
Status report / roadmap
http://www.fickr.com/photos/brianatwebbmoto/2392041992/sizes/m/
Core functionality
Schema serialization
Automatic formgeneration
Portlet assignments
Content rules
Relations
• Support for referencing Dexterity content from AT content is in progress
Widgets
• Not as rich as Archetypes yet, but better than formlib. We have autocomplete, browse-for-content, file/image upload.
TTW schema editing
Image & file support
(via plone.namedfile)
Text transform support
(via plone.app.textfield)
WebDAV support
Versioning & staging
• In progress
TTW behavior creation
Automatic migrationfrom Archetypescontent
Multi-lingual content
• Some discussion, but no code yet.
Link integrity checks
Upcoming releases
• First beta release was on Apr. 20• But, being used in production• Future releases will support upgrades
Compatibility
• Plone 3• Plone 4
Performance
Further information
• Installation howto: http://plone.org/products/dexterity/documentation/how-to/install
• Dexterity manual:
http://plone.org/products/dexterity/documentation/manual/developer-manual
• Behaviors manual:
http://plone.org/products/dexterity/documentation/manual/behaviors
Example Code
• example.dexterity• example.conference• example.dexgallery
(in the collective)
Thanks to everyone who has contributed to making Dexterity a reality!
http://www.fickr.com/photos/torley/2862255105/
Getting involved
• Google Code project:http://code.google.com/p/dexterity/
• Google Group:http://groups.google.com/group/dexterity-development