初速1PV

プログラミングにまつわることの記録

Flask-wtfでvalidatorsの追加

この記事はFlask-wtf (WTForms)で既存のvalidatorの追加から自作のvalidatorを作成してユ一ザ一名の重複を検知する流れについてのメモです。

対象とする読者

以下の記事を読んだことのある方やドキュメントを眺めたりして大体の使い方を知っている方

validatorの追加

WTForm(ここではflaskの拡張を使っている)のvalidationにはvalidatorsを指定してvalidationを追加することができる。以下のSigupFormはvalidationが何も無い例。

from flask_wtf import FlaskForm
from wtforms import TextField, TextAreaField
class SignupForm(FlaskForm):
    name = TextAreaField("ユ一ザー名", validators=[])
    email = TextAreaField("メ一ルアドレス", validators=[])

以下はそれらしいチェックを加えたもの。 Required, Length, regexを使っている。それぞれのチェックが失敗するとmessageがfieldのerrorsに追加されていく。

from flask_wtf import FlaskForm
from wtforms import Form, TextField, TextAreaField, FileField, PasswordField
from wtforms.validators import Required, Length, regexp
class SignupForm(FlaskForm):
    name = TextAreaField("ユ一ザー名", validators=[
        Required("回答を入力してください"),
        Length(min=3, max=30, message="ユ一ザ一名は3文字以上30文字以内にしてください")
    ])
    email = TextAreaField("メ一ルアドレス", validators=[
        Required("回答を入力してください"),
        Length(min=1, max=50, message="メ一ルアドレスは50文字以内にしてください"),
        regexp(
            '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$',
            message="無効なメ一ルアドレスです"
        ),
    ])

自分でvalidatorを作る場合はformとfieldをそれぞれ受け取る関数を与えてやれば良い。たとえば上記のフォ一ムのnameがDB上で一意な値であってほしい時はそれを判定する関数を作り、validatorsの要素にする。 以下がその例で、User.exists_by_nameは名前の通り、nameでユ一ザ一が存在するかをTrueFalseで返す関数。

def unique_user(form, user):
    if User.exists_by_name(user.data):
        user.errors += ['入力したユ一ザ一名は既に使用されています']
        return False
    return True

class SignupForm(FlaskForm):
    name = TextAreaField("ユ一ザー名", validators=[
        # 省略,
        unique_user
    ])
    email = TextAreaField("メ一ルアドレス", validators=[        
        # 省略
    ])

あとはエラ一があればそれを適当に表示させれば完了

    {% for err in form.name.errors %}
    <span>{{err}}</span><br>
    {% endfor %}

ちなみにformの利用方法とかは↓みたいにnot form.validate()で十分なはず。 ここでFalse になれば勝手に各フィ一ルドの errors にエラ一の内容が入ってくれる。

@app.route('/signup', methods=['GET'])
def signup_get():
    form = SignupForm(request.form)
    return render_template('signup.html', form=form)

@app.route('/signup', methods=['POST'])
def signup():
    form = SignupForm(request.form)
    if not form.validate():
        return render_template('signup.html', form=form)
    # ...

参考