domruf
domruf

Reputation: 1563

list the fields of a dexterity object

I'd like to list all the fields (and the values) of a dexterity object.

I can easily access a single field value like this myobject.myfield

But I don't know how to list all the available fields of an object.

Upvotes: 8

Views: 2324

Answers (6)

wolfrevo
wolfrevo

Reputation: 7293

You can use iterSchemata and getFieldsInOrder:

from plone.dexterity.utils import iterSchemata
from zope.schema import getFieldsInOrder

for schema in iterSchemata(obj):
    print(u'  %s' % schema)
    for field in getFieldsInOrder(schema):
        print(u'    %s\t%s' % field)

if obj is a Document it outputs

plone.dexterity.schema.generated.Plone_5_1643036771_2_583572_0_Document
plone.app.dexterity.behaviors.discussion.IAllowDiscussion
  allow_discussion    plone.app.dexterity.behaviors.discussion.IAllowDiscussion.allow_discussion
plone.app.dexterity.behaviors.exclfromnav.IExcludeFromNavigation
  exclude_from_nav    plone.app.dexterity.behaviors.exclfromnav.IExcludeFromNavigation.exclude_from_nav
plone.app.dexterity.behaviors.id.IShortName
  id  plone.app.dexterity.behaviors.id.IShortName.id
plone.app.dexterity.behaviors.metadata.IDublinCore
  title       plone.app.dexterity.behaviors.metadata.IBasic.title
  description plone.app.dexterity.behaviors.metadata.IBasic.description
  subjects    plone.app.dexterity.behaviors.metadata.ICategorization.subjects
  language    plone.app.dexterity.behaviors.metadata.ICategorization.language
  effective   plone.app.dexterity.behaviors.metadata.IPublication.effective
  expires     plone.app.dexterity.behaviors.metadata.IPublication.expires
  creators    plone.app.dexterity.behaviors.metadata.IOwnership.creators
  contributors        plone.app.dexterity.behaviors.metadata.IOwnership.contributors
  rights      plone.app.dexterity.behaviors.metadata.IOwnership.rights
plone.app.contenttypes.behaviors.richtext.IRichTextBehavior
  text        plone.app.contenttypes.behaviors.richtext.IRichTextBehavior.text
plone.app.relationfield.behavior.IRelatedItems
  relatedItems        plone.app.relationfield.behavior.IRelatedItems.relatedItems
plone.app.versioningbehavior.behaviors.IVersionable
  changeNote  plone.app.versioningbehavior.behaviors.IVersionable.changeNote
  versioning_enabled  plone.app.versioningbehavior.behaviors.IVersionable.versioning_enabled
plone.app.contenttypes.behaviors.tableofcontents.ITableOfContents
  table_of_contents   plone.app.contenttypes.behaviors.tableofcontents.ITableOfContents.table_of_contents

Upvotes: 1

rodfersou
rodfersou

Reputation: 944

Figure out how to list all fields from fields and behaviors:

from plone.behavior.interfaces import IBehavior
from plone.dexterity.interfaces import IDexterityFTI
from zope.component import getUtility


def get_fields(portal_type):
    fti = getUtility(IDexterityFTI, name=portal_type)
    schema = fti.lookupSchema()
    fields = schema.names()
    for bname in fti.behaviors:
        factory = getUtility(IBehavior, bname)
        behavior = factory.interface
        fields += behavior.names()
    return fields

Upvotes: 1

Maurizio Delmonte
Maurizio Delmonte

Reputation: 71

as David noted, I could not find a way to enumerate the fields coming from behaviors.

So, digging into plone.dexterity, in utils.getAdditionalSchemata function I found this way to roughly solve the problem:

from zope.schema import getFieldsInOrder
from plone.behavior.interfaces import IBehaviorAssignable

behavior_assignable = IBehaviorAssignable(context)
if behavior_assignable:
  behaviors = behavior_assignable.enumerateBehaviors()
  for behavior in behaviors:
    for k,v in getFieldsInOrder(behavior.interface):
      # ...

Upvotes: 7

domruf
domruf

Reputation: 1563

I found a way to do it. Since the dexterity scheme varies I could not use Christophs suggestion directly. But this works now

for key, value in getFieldsInOrder(obj.getTypeInfo().lookupSchema()):
    value = getattr(getattr(obj, key), 'output', getattr(obj, key))

Upvotes: 5

Martijn Pieters
Martijn Pieters

Reputation: 1121356

Dexterity objects are defined by a schema, which is enumerable:

from zope.interface.interfaces import IMethod

for name, desc in IYourDexteritySchema.namesAndDescriptions():
    value = getattr(yourDexterityInstance, name)
    if IMethod.providedBy(desc):
        # It's a method, call it
        value = value()

Here I use the .namesAndDescriptions() method, but you can also just use the interface as an iterator if you don't have any methods on your schema:

for name in IYourDexteritySchema:
    value = getattr(yourDexterityInstance, name)

Last but not least, zope.schema has a utility method named getFieldsInOrder that will filter on zope.schema fields in an interface; the above methods also list methods and non-schema attributes, getFieldsInOrder only lists zope.schema specific attribute types:

from zope.schema import getFieldsInOrder

for name, field in getFieldsInOrder(IYourDexteritySchema):
    value = getattr(yourDexterityInstance, name)

If you defined the schema through-the-web, you may not know how to look up the interface for your type. You can also retrieve the schema interface through the Factory Type Information, or FTI for short:

from plone.dexterity.interfaces import IDexterityFTI
from zope.component import getUtility

schema = getUtility(IDexterityFTI, name='your.dexterity.type').lookupSchema()

where schema now holds your interface.

Upvotes: 8

Christoph Böhner
Christoph Böhner

Reputation: 421

You can alternatively use the FTI:

from plone.dexterity.interfaces import IDexterityFTI
from zope.component import getUtility

fti = getUtility(IDexterityFTI, name='rgd.venues.venue')
schema = fti.lookupSchema()
fields = getFieldsInOrder(schema)
for key, value in fields:
    # so something

Upvotes: 1

Related Questions