我正在尝试创建一个自定义小部件以用于 zope.schema.Dict 字段。键会自动从用户列表中提取,值将是选定词汇之一。我的大部分工作或多或少都在工作,但我的问题是保存表单时。我正在使用 plone.app.registry.browser.controlpanel.RegistryEditForm 视图,并且架构包含有问题的 Dict 字段。我收到以下错误:
Traceback (innermost last):
Module ZPublisher.Publish, line 60, 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 138, in update
Module z3c.form.action, line 99, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.app.registry.browser.controlpanel, line 55, in handleSave
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 zope.component.hooks, line 104, in adapter_hook
Module z3c.form.converter, line 79, in FieldWidgetDataConverter
Module zope.component._api, line 120, in queryMultiAdapter
Module zope.component.registry, line 238, in queryMultiAdapter
Module zope.interface.adapter, line 532, in queryMultiAdapter
Module z3c.form.converter, line 71, in __init__
TypeError: Field ``mypackage_dict`` of type ``Dict`` must provide ``IFromUnicode``.
我尝试创建一个转换器,但我显然做错了什么。
小部件代码:
class MyPackageWidget(Widget):
implementsOnly(IMyPackageWidget)
klass = u'mypackage-widget'
input_template = ViewPageTemplateFile("input.pt")
def render(self):
if self.mode == INPUT_MODE:
return self.input_template()
def users(self):
utility = getUtility(IMyPackageUtility)
frequencies = utility.frequencies()
for usr in plone.api.user.get_users():
user_id = usr.getId()
yield {'id': user_id,
'myvalue': frequencies.get(user_id),
'name': usr.getProperty('fullname') or user_id}
def extract(self, default=NO_VALUE):
field_key = self.name + '.'
myvalues = {}
for key in self.request.keys():
if key.startswith(field_key):
user_id = safe_unicode(key[len(field_key):])
value = self.request.get(key)
myvalues[user_id] = value
return myvalues
def options(self):
for term in frequencies._terms:
yield {'value': term.value,
'content': term.title}
@adapter(IDict, IFormLayer)
@implementer(IFieldWidget)
def MyPackageFieldWidget(field, request):
""" IFieldWidget factory for MyPackageWidget
"""
return FieldWidget(field, MyPackageWidget(request))
class MyPackageDataConverter(BaseDataConverter):
"""Convert between the context and the widget"""
adapts(IDict, IMyPackageWidget)
def toWidgetValue(self, value):
return value
def toFieldValue(self, value):
return value
转换器实际上还没有做任何事情。我不确定它需要做什么,但我在这些方法中放置了一个堆栈跟踪,它只是从一开始就没有被击中。我确实验证了提取代码将数据格式化为有意义的内容,并且应该满足我定义的字段。
zcml:
<class class=".widgets.MyPackageWidget">
<require
permission="zope.Public"
interface="my.package.interfaces.widget.IMyPackageWidget"
/>
</class>
<adapter
factory=".widgets.MyPackageDataConverter"
/>
<adapter
factory=".widgets.MyPackageFieldWidget"
provides="z3c.form.interfaces.IFieldWidget"
for="zope.schema.interfaces.IDict
zope.schema.interfaces.IField
my.package.interfaces.widget.IWidgetsLayer"
/>
<z3c:widgetTemplate
mode="input"
widget="my.package.interfaces.widget.IMyPackageWidget"
layer="my.package.interfaces.widget.IWidgetsLayer"
template="input.pt"
/>
</configure>
plone.supermodel.model.Schema 模式的摘录
form.widget(member_frequencies=MyPackageFieldWidget)
mypackage_dict = schema.Dict(
title=_(u"Member/subscription"),
key_type=schema.TextLine(),
value_type=schema.Choice(source=setting_options),
)
如果我创建一个 plone.directives.form.SchemaForm ,我为 data['mypackage_dict'] 返回的值看起来很好,我可以将它保存到注册表中。不过,如果我能理解它试图转换的内容,我希望能够使用 controlpanel.RegistryEditForm 类来实现更多自动化。
克隆 4.2