Виджет z3c для поля dict

Я пытаюсь создать собственный виджет для использования с полем 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, значение, которое я возвращаю для данных ['mypackage_dict'], выглядит нормально, и я могу сохранить его в реестре. Я хотел бы быть в состоянии автоматизировать это больше, используя класс controlpanel.RegistryEditForm, хотя, если я могу понять, что он пытается преобразовать.

Plone 4.2

0 ответов

Другие вопросы по тегам