开发者

Vocabulary source, function is not iterable, with dexterity in Plone 4.1

I have a custom Dexterity content type with collective.z3c.datagridfield define in the following way:

class ILanguageRow(Interface):
    # Interface that defines a datagrid row.
    lang = schema.Choice(
        title=_(u'Language'), required=True, 
       开发者_JS百科 source=my_languages,
        default=u'en',
    )

(...)

This it the function that returns the vocabulary, as in http://plone.org/products/dexterity/documentation/manual/schema-driven-forms/customising-form-behaviour/vocabularies

@grok.provider(IContextSourceBinder)
def languages(context):
    """
    Return a vocabulary of language codes and
    translated language names.
    """

    # z3c.form KSS inline validation hack
    if not ISiteRoot.providedBy(context):
        for item in getSite().aq_chain:
            if ISiteRoot.providedBy(item):
                context = item

    # retrieve the localized language names.
    request = getRequest()
    portal_state = getMultiAdapter((context, request), name=u'plone_portal_state')
    lang_items = portal_state.locale().displayNames.languages.items()

    # build the dictionary
    return SimpleVocabulary(
        [SimpleTerm(value=lcode, token=lcode, title=lname)\
          for lcode, lname in sorted(lang_items) if lcode in config.CV_LANGS]
    )

Inside the Edit and Add Form, the Choice field works correctly. But when I attempt to save the content:

TypeError: argument of type 'function' is not iterable
2011-07-08 13:37:40 ERROR Zope.SiteErrorLog 1310125060.840.103138625259 http://localhost:8081/Plone/++add++my.content.types.curriculum
Traceback (innermost last):
  Module ZPublisher.Publish, line 126, in publish
  Module ZPublisher.mapply, line 77, in mapply
  Module ZPublisher.Publish, line 46, in call_object
  Module plone.z3cform.layout, line 70, in __call__
  Module plone.z3cform.layout, line 54, in update
  Module my.content.types.curriculum, line 356, in update
  Module plone.z3cform.fieldsets.extensible, line 59, in update
  Module plone.z3cform.patch, line 30, in GroupForm_update
  Module z3c.form.group, line 134, in update
  Module z3c.form.group, line 47, in update
  Module z3c.form.group, line 43, in updateWidgets
  Module z3c.form.field, line 275, in update
  Module z3c.form.browser.multi, line 61, in update
  Module z3c.form.browser.widget, line 70, in update
  Module z3c.form.widget, line 396, in update
  Module z3c.form.widget, line 88, in update
  Module z3c.form.widget, line 390, in set
  Module collective.z3cform.datagridfield.datagridfield, line 112, in updateWidgets
  Module collective.z3cform.datagridfield.datagridfield, line 90, in getWidget
  Module z3c.form.browser.widget, line 70, in update
  Module z3c.form.object, line 213, in update
  Module z3c.form.widget, line 88, in update
  Module collective.z3cform.datagridfield.datagridfield, line 216, in set
  Module z3c.form.object, line 229, in applyValue
  Module z3c.form.validator, line 67, in validate
  Module zope.schema._bootstrapfields, line 153, in validate
  Module zope.schema._field, line 325, in _validate
TypeError: argument of type 'function' is not iterable

Why is this happening?


This happens when the field hasn't been bound or is missing the context. Normally validation will happen against a "bound" field (bound = field.bind(context)) so that your context-aware vocabulary can be turned into a static vocabulary for this context. It'll still be a function (not called with the context) when this didn't take place.

I am not familiar enough with the datagrid widget setup to pinpoint where this goes wrong, but it appears that it generates widgets on-the-fly and I suspect it doesn't bind the fields for these correctly. Take a look at DataGridField.getWidget method of the collective.z3cform.datagridfield.datagridfield module and try to figure out what's going on there with a debugger and / or file a bug with the authors of the package.


I solved the problem by providing my custom vocabulary as a Named Vocabulary, in this way:

from Products.CMFCore.interfaces import ISiteRoot
from zope.component import getMultiAdapter
from zope.site.hooks import getSite
from zope.globalrequest import getRequest

from my.content import config

class LanguagesVocabulary(object):

    grok.implements(IVocabularyFactory)

    def __call__(self, context):
        # z3c.form KSS inline validation hack
        if not ISiteRoot.providedBy(context):
            for item in getSite().aq_chain:
                if ISiteRoot.providedBy(item):
                    context = item

        # retrieve the localized language names.
        request = getRequest()
        portal_state = getMultiAdapter((context, request), name=u'plone_portal_state')
        lang_items = portal_state.locale().displayNames.languages.items()

        # build the dictionary
        terms = [SimpleTerm(value=lcode, token=lcode, title=lname)\
          for lcode, lname in sorted(lang_items) if lcode in config.CV_LANGS]

        return SimpleVocabulary(terms)

grok.global_utility(LanguagesVocabulary, name=u"my.content.LanguagesVocabulary")

and in my Dexterity content type schemata:

class ILanguageRow(Interface):
    # Interface that defines a datagrid row.
    lang = schema.Choice(
        title=_(u'Language'), required=True, 
        vocabulary=u"my.content.LanguagesVocabulary",
    )

This way it works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜