0

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」は一度だけ実行されます(スキーマの初期化中などに推測します)。

ユーザー入力の「コード」を確認するたびに実行する必要がありますが、どうすればよいですか?

助けてくれてありがとう

4

2 に答える 2

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 ステートメントを追加しました。RefreshBeforeContainsCheckクラスは次のように使用できます

class ItemsEditSchema(Schema):
    code = validators.OneOf(RefreshBeforeContainsCheck(getActiveCodes))
    allow_extra_fields = True

バリデータスキーマで。

上記の実装方法では、バリデーターがテストを実行するgetActiveCodesたびに関数が呼び出されます(ここで、クラスは として機能します) 。これで、検証が失敗した場合、バリデーターは のすべての要素をリストしたエラー メッセージを生成します。その場合は、実装によって処理されます。検証エラーが発生した場合にデータベースを 2 回呼び出すのを避けるために、「データベース」の結果リストを としてキャッシュすることにしましたが、それが適切かどうかはニーズによって異なります。OneOfitem in listlistRefreshBeforeContainsCheck.__contains__OneOflist__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)})
于 2015-10-26T09:24:39.487 に答える
0

最後に、OneOf を使用する代わりに FancyValidtor を書きました。これが私のコードです。

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
于 2015-11-08T10:37:22.547 に答える