Flaskでのフォーム作成にはFlask-WTFを利用するとWTFormのバリデーションの利用に加えてCSRFトークンを生成・検証してくれます。
フォームを表などで用意するときは行単位で複製できると便利なのですが、Flask-WTFでこれを行う場合は少し注意が必要です。
複製する子フォームではCSRFトークンを生成しないようにする必要があります。
app.py
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import FormField, FieldList, IntegerField, StringField, SubmitField
from wtforms.validators import Required
app = Flask(__name__)
app.secret_key = 'HardToGuess'
class MemberForm(FlaskForm):
def __init__(self, *args, **kwargs):
kwargs['csrf_enabled'] = False # 子フォームではCSRFトークンが生成されないように設定
super(MemberForm, self).__init__(*args, **kwargs)
m_name = StringField('name', validators=[Required()])
score = IntegerField('id', validators=[Required()])
class TeamForm(FlaskForm):
members = FieldList(FormField(MemberForm, 'Member'), min_entries=2, max_entries=10)
"""
FieldlistとFormFieldを用いて子フォーム複製
"""
submit = SubmitField('送信')
@app.route('/', methods=['POST','GET'])
def index():
form = TeamForm()
print(request.form) # チェック用
if form.validate_on_submit():
print('Validated')
print(form.members.data)
else:
print('NOT Validated')
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
index.html
<form action="" method="post">
{{ form.csrf_token() }}
<h1>Flask-WTF Fieldlistサンプル</h1>
<table>
<tr>
<td>ID</td>
<td>名前</td>
<td>点数</td>
{% for member in form.members %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ member.m_name() }}</td>
<td>{{ member.score() }}</td>
</tr>
{% endfor %}
</table>
{{ form.submit() }}
</form>
flask_wtf.FlaskForm
からではなく、 wtf.Form
を継承して作成しても同じことができそうです。