formencode 中嵌套自定义验证器的模式

2 投票
2 回答
1114 浏览
提问于 2025-04-16 17:10

我想在我的模式里嵌套自定义的验证器,像这样:

MySchema(Schema):
    class MyValidator(validators.FancyValidator):
        def _to_python(self, value, state):
            ...
    class MyOtherValidator(validators.FancyValidator):
        def _to_python(self, value, state):
            ...

    field_foo = All(validators.NotEmpty(),
                    MyValidator())
    field_bar = All(validators.NotEmpty(),
                    MyOtherValidator())

但是,它似乎把 MyValidatorMyOtherValidator 当成了字段,因为 form_errors 里包含了:

{ 
  'MyValidator': 'Missing value',
  'MyOtherValidator': 'Missing value'
}

如果我不嵌套它们,它们看起来就没问题。我漏掉了什么呢?

2 个回答

0

在Python中,你在类里定义的任何东西都叫做字段。无论是静态变量、用self设置的变量、方法还是类本身。

如果你想“隐藏”某些类,或者让它们“少一些公开”,用Python的说法就是,你应该在它们的名字前面加上两个下划线__。

>>> dir(X())
['A', '_B', '_X__C', '__doc__', '__module__']
>>> class X:
...     class A: pass
...     class __B: pass
...     c = 0
...     __d = 1
... 
>>> dir(X())
['A', '_X__B', '_X__d', '__doc__', '__module__', 'c']

如你所见,这种隐私设置其实有个漏洞,但大多数自动工具会识别出你是在尝试让某些东西变得私密。

2

我的建议是:你应该把FancyValidator这个子类的定义放到全局范围内,具体来说,可以选择(1)在同一个模块中,把它放在Schema定义之前,或者(2)放在一个单独的模块里,这样可以更方便地重复使用。除非有特别的理由需要嵌套,否则在模块的命名空间中多几个类名是没问题的。

举个例子:

from formencode import All, FancyValidator, Schema, validators

class MyValidator(FancyValidator):
    def _to_python(self, value, state):
        return value + '_foo'

class MyOtherValidator(FancyValidator):
    def _to_python(self, value, state):
        return value + '_bar'

class MySchema(Schema):
    field_foo = All(validators.NotEmpty(), MyValidator())
    field_bar = All(validators.NotEmpty(), MyOtherValidator())

print MySchema().to_python({'field_foo': 'x', 'field_bar': 'y'}, None)

结果:

{'field_foo': 'x_foo', 'field_bar': 'y_bar'}

撰写回答