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 ステートメントを追加しました。RefreshBeforeContainsCheck
クラスは次のように使用できます
class ItemsEditSchema(Schema):
code = validators.OneOf(RefreshBeforeContainsCheck(getActiveCodes))
allow_extra_fields = True
バリデータスキーマで。
上記の実装方法では、バリデーターがテストを実行するgetActiveCodes
たびに関数が呼び出されます(ここで、クラスは として機能します) 。これで、検証が失敗した場合、バリデーターは のすべての要素をリストしたエラー メッセージを生成します。その場合は、実装によって処理されます。検証エラーが発生した場合にデータベースを 2 回呼び出すのを避けるために、「データベース」の結果リストを としてキャッシュすることにしましたが、それが適切かどうかはニーズによって異なります。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)})