我正在使用formencode 1.3.0a1(以及turbogeras 2.3.4)并遇到验证器OneOf的问题。
我想根据数据库中的列表验证一些输入。 这是我的验证模式和获取列表的方法:
from formencode import Schema, validators
def getActiveCodes():
codes = DBSession.query(SomeObject.code).all()
codes = [str(x[0]) for x in codes]
return codes
class itemsEditSchema(Schema):
code = validators.OneOf(getActiveCodes())
allow_extra_fields = True
方法“getActiveCodes”只执行一次(我想在架构初始化期间或类似的东西)。
每当我想检查用户输入的“代码”时,我都需要它运行,我该怎么做?
感谢您的帮助
答案 0 :(得分:1)
我不知道如何让 formencode 做你所要求的。但是,由于这是Python,我们可以做的事情几乎没有限制。
您可以通过在专用类中包含对getActiveCodes
的调用来解决此问题。包装类RefreshBeforeContainsCheck
将实现特殊方法__iter__
和__contains__
,以提供用作可迭代对象的必要接口:
from formencode import Schema, validators, Invalid
class RefreshBeforeContainsCheck(object):
def __init__(self, func):
self._func = func
self._current_list = None
def __iter__(self):
print '__iter__ was called.'
#return iter(self._func()) # Could have refreshed here too, but ...
return iter(self._current_list)
def __contains__(self, item):
print '__contains__ was called.'
self._current_list = self._func() # Refresh list.
return item in self._current_list
我添加了print语句,以便更清楚地了解它在运行时的行为方式。然后可以像{/ p>一样使用RefreshBeforeContainsCheck
类
class ItemsEditSchema(Schema):
code = validators.OneOf(RefreshBeforeContainsCheck(getActiveCodes))
allow_extra_fields = True
在验证程序架构中。
上面实现的方式,每次getActiveCodes
验证器执行OneOf
测试(我们的类充当item in list
)时,都会调用list
函数,因为这会导致RefreshBeforeContainsCheck.__contains__
被调用。现在,如果验证失败,OneOf
验证器会生成一条错误消息,列出list
的所有元素;该案例由我们的__iter__
实施处理。为避免在验证错误的情况下调用数据库两次,我选择缓存"数据库"结果列表为self._current_list
,但是否合适取决于您的需求。
我已经为此创建了一个要点:https://gist.github.com/mtr/9719d08f1bbace9ebdf6,基本上创建了一个使用以下代码使用上述代码的示例。
def getActiveCodes():
# This function could have performed a database lookup.
print 'getActivityCodes() was called.'
codes = map(str, [1, 2, 3, 4])
return codes
def validate_input(schema, value):
print 'Validating: value: {!r}'.format(value)
try:
schema.to_python(value)
except Invalid, error:
print 'error: {!r}'.format(error)
print
def main():
schema = ItemsEditSchema()
validate_input(schema, {'code': '3'})
validate_input(schema, {'code': '4'})
validate_input(schema, {'code': '5'})
要点的输出是:
Validating: value: {'code': '3'}
__contains__ was called.
getActivityCodes() was called.
Validating: value: {'code': '4'}
__contains__ was called.
getActivityCodes() was called.
Validating: value: {'code': '5'}
__contains__ was called.
getActivityCodes() was called.
__iter__ was called.
error: Invalid("code: Value must be one of: 1; 2; 3; 4 (not '5')",
{'code': '5'}, None, None,
{'code': Invalid(u"Value must be one of: 1; 2; 3; 4 (not '5')",
'5', None, None, None)})
答案 1 :(得分:0)
最后我用FancyValidtor而不是OneOf,这是我的代码:
class codeCheck(FancyValidator):
def to_python(self, value, state=None):
if value==None:
raise Invalid('missing a value', value, state)
return super(codeCheck,self).to_python(value,state)
def _validate_python(self, value, state):
codes = DBSession.query(Code).all()
if value not in codes:
raise Invalid('wrong code',value, state)
return value
class itemsEditSchema(Schema):
code = codeCheck ()
allow_extra_fields = True