WTForm,FlaskFormを使ってみたい
FlaskFormを使うにあたり、あまり記事がなかったので備忘録もかねて記事にします。
入力フォームで送られてきたデータを受け取る動きを例にします
まず下準備
from flask import Flask
from flask_wtf import FlaskForm
from wtforms import (StringField, PasswordField, BooleanField,
RadioField, SelectField,SubmitField, ValidationError)
フィールドの例
StringField
: 文字列
PasswordField
: パスワード
BooleanField
: チェックボックス
RadioField
: ラジオボタン
SelectField
: セレクトボックス
SubmitField
: 送信ボタン
ValidationError
: エラー表示
class signup_form(FlaskForm):
"""登録フォームに関するvalidate関数"""
name = StringField(label=('名前'))
password = PasswordField(label=('パスワード'))
gender = RadioField(label='性別', choices=[
('1', '男性'), ('2', '女性'), ('0', 'その他')])
birth = SelectField(label=('誕生年'),
choices=[
('', '選択してください'),
('2021', '令和3年'),
('2022', '令和4年')
])
shikaku1 = BooleanField(label=('基本情報技術者試験(FP)'),
false_values=(False, 'false', 0, '0'))
shikaku2 = BooleanField(label=('応用情報技術者試験(AP)'),
false_values=(False, 'false', 0, '0'))
submit = SubmitField(label=('登録'))
# とりあえず使ってない、 htmlのsubumitでも動く
def validate_name(self, name):
""" name を検証 """
if name.data == "":
# if 〇〇の エラーコードを出す
raise ValidationError('入力してください')
if "/" in name.data:
raise ValidationError('名前に「/」は含められません')
if len(name.data) > 20:
raise ValidationError('文字数が多すぎます')
def validate_password(self, password):
pw_pat = re.compile("^[0-9a-zA-Z]+$")
if password.data == "":
raise ValidationError('入力してください')
if len(password.data) < 8 or len(password.data) > 25:
raise ValidationError('8文字以上25文字以下')
if not pw_pat.match(password.data):
raise ValidationError('使用できない文字が含まれています')
def validate_gender(self, gender):
if gender.data is None:
raise ValidationError('選択してください')
def validate_birth(self, birth):
if ken_code.data == "":
raise ValidationError('選択してください')
フォームクラスを定義して、バリデーション内容をif文で追加していきます。
設定したバリデーションに引っかからなければ、正しい値として送られます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>登録</title>
<h1>登録情報を入力</h1>
</head>
<body>
<h2>{{ message }}</h2>
<form method="POST" action="/registrate">
{{ form.csrf_token }}
{{ form.hidden_tag() }}
<!-- 名前 -->
<div style="margin: 10px;">
{{ form.name.label }}</br>
{% if form.name.errors %}
<span style="color: red;">{{ form.name.errors[0] }}</span></br>
{% endif %}
{{ form.name(placeholder="田中太郎") }}
</div>
<!-- パスワード -->
<div style="margin: 10px;">
{{ form.password.label }}</br>
{% if form.password.errors %}
<span style="color: red;">{{ form.password.errors[0] }}</span></br>
{% endif %}
{{ form.password(placeholder="8文字以上25字以下") }}
</div>
<!-- 性別 -->
<div style="margin: 10px;">
{{ form.gender.label }}</br>
{% if form.gender.errors %}
<span style="color: red;">{{ form.gender.errors[1] }}</span></br>
{% endif %}
{% for subgender in form.gender %}
<tr>
<td>
{{ subgender}}
</td>
<td>
{{ subgender.label }}
</td>
</tr>
{% endfor %}
</div>
<!-- 生まれ年 -->
<div style="margin: 10px;">
{{ form.birth.label }}</br>
{% if form.birtherrors %}
<span style="color: red;">{{ form.birth.errors[0] }}</span></br>
{% endif %}
{{ form.birth}}
</div>
<!-- 取得資格 -->
<div style="margin: 10px;">
取得資格</br>
{{ form.shikaku1 }}
{{ form.shikaku1.label }}
</br>
{{ form.shikaku2 }}
{{ form.shikaku2.label }}
</br>
</div>
<div style="margin: 10px;">
<input type="submit" value="送信">
</div>
</form>
</body>
</html>
@app.route('/')
def signup():
"""会員登録ページを表示"""
form = signup_form(request.form)
return render_template(
'signup.html',
form=form
)
@app.route('/registrate', methods=['POST'])
def registrate():
"""登録情報を受け取る"""
form = signup_form()
if form.validate_on_submit():
# validateを通過したら
name = form.name.data,
password = form.password.data,
gender = form.gender.data,
birth = form.birth.data,
if form.shikaku1.data != 0:
shikaku1 = form.shikaku1.data
if form.shikaku2.data != 0:
shikaku2 = form.shikaku2.data
return redirect('/')
# validat通過できなければ入力フォームに戻す
message = "バリデーションによる阻止"
return render_template(
"signup.html",
form=form,
message=message
)
ちなみに、入力フォームに最初から値を入れておきたい場合(placeholderではなくvalueの方)
form.変数名.data = 表示させたい値
と書いておくといい。
@app.route('/')
def signup():
"""会員登録ページを表示"""
form = signup_form(request.form)
form.name.data = '田中太郎'
form.gender.data = '1'
form.birth.data = '2021'
form.shikaku1.data = True # checked
form.shikaku2.data = False
return render_template(
'signup.html',
form=form
)
BooleanFieldは名前の通りbool値を返すフィールド。
チェックがあればTrue,チェックがなければFalseを返します。
今回はsignup_form()という関数を作りましたが、例えば入力項目を減らしてログインフォームなどに流用しようとすると、validation関数のところで引っかかってエラーになります。
参考にした記事など
FlaskFormで簡単にバリデーションする方法 https://qiita.com/kotamatsuoka/items/c93129f6ade5974dc122
【Python】Flask+WTFormsで簡単にフォームを作成する https://hirahira.blog/flask-wtforms/
Flask Form Validation with Flask-WTF https://stackabuse.com/flask-form-validation-with-flask-wtf/
WTForm公式ドキュメント https://wtforms.readthedocs.io/en/2.3.x/