自定义小部件与词汇表相关的错误

时间:2011-11-04 05:00:26

标签: plone widget dexterity

我有两种敏捷内容类型 - 参与者&标准 - 后者用于确定参与者包含在项目中。条件作为 RelationList 存储在Participant上,但是我想用基于复选框的默认选择器小部件替换默认的选择器小部件。我已经创建了一个自定义窗口小部件,我将其分配给条件字段,该窗口会将正确的条件显示为复选框,但在验证时会出现以下错误:

2011-11-04 00:27:26 ERROR Zope.SiteErrorLog 1320380846.610.720672558798 http://192.168.2.128:8080/ctcc/Trials/trial1/sites/site1/++add++ctcc.Participant
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 plone.z3cform.fieldsets.extensible, line 59, in update
  Module plone.z3cform.patch, line 30, in GroupForm_update
  Module z3c.form.group, line 125, in update
  Module z3c.form.form, line 134, in updateWidgets
  Module z3c.form.field, line 275, in update
  Module z3c.form.browser.checkbox, line 44, in update
  Module z3c.form.browser.widget, line 70, in update
  Module z3c.form.widget, line 200, in update
  Module z3c.form.widget, line 84, in update
  Module z3c.form.widget, line 216, in extract
AttributeError: 'list' object has no attribute 'getTermByToken'

我已经像这样定义了小部件:

class ICriteriaListingWidget(Interface):
    """Marker interface for the criteria listing widget"""

class CriteriaSelectionWidget(CheckBoxWidget):
    implements(ICriteriaListingWidget)
    klass = u'criteria-listing-widget'
    input_template = ViewPageTemplateFile('criteria_listing_input.pt')
    display_template = ViewPageTemplateFile('criteria_listing_display.pt')

    @property
    def terms(self):
        catalog = getToolByName(self.context, 'portal_catalog')
        content = catalog(
            portal_type='ctcc.Criterion',
        )
        return [SimpleTerm(x.id, x, title=x.Title) for x in content]

@adapter(IRelationList, IFormLayer)
@implementer(IFieldWidget)
def CriteriaListingWidget(field, request):
    return FieldWidget(field, CriteriaSelectionWidget(request))

然后在Participant Dexterity类型上,该字段为:

form.widget(criteria=CriteriaListingWidget)
criteria = RelationList(
    title = _(u'Inclusion Criteria'),
    description = _(u'The participant criteria evaluated against for inclusion'),
    value_type = RelationChoice(
        source = ObjPathSourceBinder(
            object_provides = ICriterion.__identifier__,
        ),
    ),
    default = [],
    required = False,
)

鉴于错误的性质,我用自定义词汇表替换了 ObjPathSourceBinder 源,希望它能返回具有正确接口的对象,但我看到使用该解决方案的完全相同的错误

更新:我已根据建议将术语列表包装在SimpleVocabulary中,但它只是将问题转移到了。请注意,错误现在发生在 kss_z3cform_inline_validation 中。

2011-11-06 19:24:36 ERROR Zope.SiteErrorLog 1320625476.430.209960132592 http://192.168.2.128:8080/ctcc/Trials/trial1/sites/site1/kss_z3cform_inline_validation
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 <wrapper>, line 5, in wrapper
  Module kss.core.actionwrapper, line 236, in apply
  Module plone.app.z3cform.kss.validation, line 51, in validate_input
  Module z3c.form.group, line 92, in extractData
  Module z3c.form.form, line 145, in extractData
  Module z3c.form.field, line 301, in extract
  Module z3c.form.converter, line 311, in toFieldValue
AttributeError: 'SimpleVocabulary' object has no attribute 'getValue'
2011-11-06 19:24:36 ERROR plone.transformchain Unexpected error whilst trying to apply transform chain

2 个答案:

答案 0 :(得分:3)

您需要返回词汇表对象,而不是列表:

from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary

# ...

class CriteriaSelectionWidget(CheckBoxWidget):
    # ...

    @property
    def terms(self):
        catalog = getToolByName(self.context, 'portal_catalog')
        content = catalog(
            portal_type='ctcc.Criterion',
        )
        return SimpleVocabulary([SimpleTerm(x.id, x, title=x.Title) for x in content])

SimpleVocabulary类为这种情况实现了正确的方法。

答案 1 :(得分:1)

我不确定这是否算作本身的答案,但我最终通过创建自定义源代码来避免对自定义小部件的需求。 SourceBinder对象。

class CTCCSource(object):
    implements(IVocabularyTokenized)

    container    = None
    content_type = None

    def __init__(self, context):
        self.context = context
        container_path = self._container_path(context)
        self.catalog = getToolByName(context, 'portal_catalog')
        self.intid_utility = getUtility(IIntIds)
        self.content = [i.getObject() for i in self.catalog(portal_type=self.content_type, path={'query': container_path})]

    def _container_path(self, context):
        physical_path = list(context.getPhysicalPath())
        trial_path = physical_path[:physical_path.index('sites')]
        criteria_path = trial_path + [self.container]
        return '/'.join(criteria_path)

    def __contains__(self, term):
        return term in self.content

    def __iter__(self):
        for crit in self.content:
            yield SimpleTerm(crit, self.intid_utility.getId(crit), crit.Title)

    def __len__(self):
        return len(self.content)

    def getTerm(self, obj):
        return SimpleVocabulary.createTerm(
            obj, self.intid_utility.getId(obj), obj.Title()
        )

    def getTermByToken(self, value):
        return self.getTerm(self.intid_utility.getObject(int(value)))

class CTCCSourceBinder(object):
    implements(IContextSourceBinder)
    source = None

    def __init__(self, **kw):
        pass

    def __call__(self, context):
        return self.source(context)

这允许我从当前上下文中包含的内容生成表单复选框字段,将所选选项的引用添加到RelatedList中。