<Python, flask> WTforms の In-line Validators

WTformsIn-line Validatorsがちとわかったのでメモっち。

validatorさんは、
WTformsでフォームFromのクラスを作って、
フォームの各要素 Field に期待された値が入って返ってくるか?を
チェック validateする役目。

あらかじめ準備してあるものは、Fieldを追加する時に引数で渡せる。

Validators — WTForms 3.0dev documentation

ソースは、

https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py

で、自分で追加したい時は、コードに次のように埋め込むことができるらしい。

def validate_hogehogehoge(self, field):

validate_という前置き prefixに続けて、対象のField名を書けばおけー。

ちと試してみる。

In [48]: from wtforms import Form, StringField

In [49]: class HageClass(Form):
    ...:     hage = StringField('Hage')
    ...:     def validate_hage(self, field):
    ...:         if 'aaa' == 'aaa':
    ...:             print('Hageeee')
    ...:             

In [50]: a = HageClass()

In [51]: a.validate()
Hageeee
Out[51]: True

ほんとだ、、、読み込まれた。

ふーん。

どうやってるんだろー、、と思ってソースをちら見。
なんか難しくてよくわからんが、この辺っぽい。

167 class FormMeta(type):
168     """
169     The metaclass for `Form` and any subclasses of `Form`.
170 
171     `FormMeta`'s responsibility is to create the `_unbound_fields` list, which
172     is a list of `UnboundField` instances sorted by their order of
173     instantiation.  The list is created at the first instantiation of the form.
174     If any fields are added/removed from the form, the list is cleared to be
175     re-generated on the next instantiation.
176 
177     Any properties which begin with an underscore or are not `UnboundField`
178     instances are ignored by the metaclass.
179     """
180     def __init__(cls, name, bases, attrs):
181         type.__init__(cls, name, bases, attrs)
182         cls._unbound_fields = None
183         cls._wtforms_meta = None
184 
185     def __call__(cls, *args, **kwargs):
186         """
187         Construct a new `Form` instance.
188 
189         Creates the `_unbound_fields` list and the internal `_wtforms_meta`
190         subclass of the class Meta in order to allow a proper inheritance
191         hierarchy.
192         """
193         if cls._unbound_fields is None:
194             fields = []
195             for name in dir(cls):
196                 if not name.startswith('_'):
197                     unbound_field = getattr(cls, name)
198                     if hasattr(unbound_field, '_formfield'):
199                         fields.append((name, unbound_field))
200             # We keep the name as the second element of the sort
201             # to ensure a stable sort.
202             fields.sort(key=lambda x: (x[1].creation_counter, x[0]))
203             cls._unbound_fields = fields

https://github.com/wtforms/wtforms/blob/master/wtforms/form.py#L173

195行目で、dir(cls)やって、アトリビュートを洗い出して、
196行目で、_で始まらないアトリビュートをより分けて、
197行目で、アトリビュートをゲットして、
198行目で、_formfieldアトリビュートがあったら、
199行目で、リスト fieldsに放り込んでる。

ふーん、、、
で、validate_hogehogeは下記のところで、収集されてるっぽい。

299     def validate(self):
300         """
301         Validates the form by calling `validate` on each field, passing any
302         extra `Form.validate_<fieldname>` validators to the field validator.
303         """
304         extra = {}
305         for name in self._fields:
306             inline = getattr(self.__class__, 'validate_%s' % name, None)
307             if inline is not None:
308                 extra[name] = [inline]
309 
310         return super(Form, self).validate(extra)

https://github.com/wtforms/wtforms/blob/master/wtforms/form.py#L299

なるほど、、、