修改或清除 zope 或 plone 中的表单输入

Modify or clean form input in zope or plone

所以基本上我想尝试 clean/filter 或清理类似于其他 python 网络框架的输入表单。具体来说,我试图从电子邮件地址中去除空格。我可以在 javascript 中做到这一点,但似乎应该有一种方法可以使用 zope 库来做到这一点。

该文档详细介绍了如何设置约束,但实际上并未详细介绍如何修改表单值。当然,问题是在我可以对空白做任何事情之前触发了约束异常。

class IEmailAddress(zope.schema.interfaces.ITextLine):
    pass

class InvalidEmailAddress(zope.schema.ValidationError):
    def __init__(self, email):
        super(InvalidEmailAddress, self).__init__(
            "'%s' is not a valid e-mail address." % email)


class EmailAddress(zope.schema.TextLine):

    zope.interface.implements(IEmailAddress)

    def constraint(self, value):
        return '\n' not in value and '\r' not in value

    def _validate(self, value):
        super(EmailAddress, self)._validate(value)
        if not is_email_address(value):
            raise InvalidEmailAddress(value)


class InviteForm(FormProvider):

    dropdown_css_class = "dropdown-spacer-left"

    def fields(self):
        """Build form fields dynamically"""
        fields = Fields(IPerson).select("name", "email")
        person = self.request.principal.person

        field['email'].field.strip() # Does not work

    @action("Invite", primary=True)
    def add_administrator(self, action, data):
        name, email = data["name"], data["email"]

        email = email.strip() # Does not work

我最后做的是使用自定义小部件功能的以下操作:

class StripTextWidget(zope.formlib.textwidgets.TextWidget):
    def _getFormInput(self):
        value = super(StripTextWidget, self)._getFormInput()
        return value.strip()

...
def fields(self):
   """Build form fields dynamically"""
   fields = Fields(IPerson).select("name", "email")
   fields["email"].custom_widget = StripTextWidget

使用 Zope 3 进行 Web 组件开发一书第 130 页也描述了这种方式

有几种不同的可能方法,具体取决于您要放置抽象层的位置。

如果你想让它相对靠近数据模型,你可以在自定义字段上定义一个 set 方法,如下所示:

    def set(self, obj, value):
        if value is not None:
            value = value.strip()
        super().set(obj, value)

这意味着任何通过架构设置字段的内容(可能是某种 API?)都会去除空白。这种方法通常用于类型转换,但将其用于这种简单的归一化似乎也不太合理。

如果您希望空白剥离成为表单视图的 属性,但仍允许合理数量的代码重用,那么您可以使用 [=15] 中建议的自定义小部件=].

最后,如果您只想拥有特定于特定表单的一些自定义行为,那么您始终可以让表单在从小部件读取数据并将其应用于基础模型之间手动处理数据,也许使用action validator, or even something more explicit if you're using zope.formlib's Edit Forms 直接调用 form.getWidgetsDataform.applyChanges 的方法。

实际上我最终是这样做的,因为它比我最初的做法更通用,后者涉及单独设置每个字段而不是全局选项。

class StripTextWidget(zope.formlib.textwidgets.TextWidget):
    def _getFormInput(self):
        value = super(StripTextWidget, self)._getFormInput()
        return value.strip()

class EmailAddress(zope.schema.TextLine):

    zope.interface.implements(IEmailAddress)
    custom_widget = StripTextWidget

    def constraint(self, value):
        return '\n' not in value and '\r' not in value

    def _validate(self, value):
        super(EmailAddress, self)._validate(value)
        if not is_email_address(value):
            raise InvalidEmailAddress(value)