【Flask】Flask-WTFの使い方と導入メリット|Chapter4-7

一つ前のページではテンプレートマクロについて学習しました。
今回は Flask-WTF について見ていきましょう。
Chapter1:Flask入門編
Chapter2:Jinja2入門編
Chapter3:フィルター編
Chapter4:フォーム編
 ・Chapter4-1:HTTPとは何か
 ・Chapter4-2:フォームの基本を理解しよう
 ・Chapter4-3:WTFormsを理解しよう
 ・Chapter4-4:フォームのバリデーションを理解しよう
 ・Chapter4-5:カスタムバリデータを理解しよう
 ・Chapter4-6:テンプレートマクロを理解しよう
 ・Chapter4-7:Flask-WTFを理解しよう ◁今回はここ
Chapter5:データベース編
Chapter6:エラーハンドリングとデバッグ編
Chapter7:アプリ開発編
Chapter4では、HTTPやフォーム、バリデーションの基礎を学びながら、Flaskでフォーム入力を処理する方法を段階的に習得してきました。
ここまでの知識を組み合わせれば、ある程度複雑なフォームの処理も可能になりますが、実際のWebアプリ開発では「安全性」や「記述の簡潔さ」も重要です。
そこで登場するのが「Flask-WTF」という拡張ライブラリです。
これを使うことで、ここまでに学んだ処理がぐっと整理され、効率的かつ安全になります。
- Flask開発を Stream Deck でボタン化しよう!
- 
Flaskは非常に軽量かつシンプルなフレームワークですが、それゆえに定型作業が多く、開発は単調な作業の連続になりがちです。 それこそがFlaskのメリットであり、習得難易度が低い理由でもありますが、単調な作業は退屈で、ミスも起こりやすいでしょう。 そこで役に立つのが Stream Deck 。 このような定型手順が多い作業を “ボタン化” することで視覚化。 圧倒的に 効率的 かつ ストレスフリー な開発環境が簡単に手に入ります↓↓ あわせて読みたいFlask開発をStreamDeckでボタン化しようあわせて読みたいプログラマー向けStream Deckの選び方|初心者でも失敗しないモデル比較ガイド
Flask-WTFとは?基本機能と導入メリットを解説

Flask-WTFの仕組みと活用ポイント
Flask-WTF とは、Flaskでフォームを扱う際に便利なライブラリ「WTForms」を、Flaskにスムーズに統合するための 拡張機能 です。
- Flask + WTForms = Flask-WTF
- 正式には flask_wtfモジュール と呼ばれる
- WTForms自体はFlask限定のものではない
これを使うことで、次のような利点があります:
- フォーム用テンプレートが簡潔になる
- request.form.get()を自分で書かなくてよい
- バリデーションの自動呼び出し
- HTMLフォームに必要な CSRFトークン の自動挿入
コード簡略化とCSRF対策を自動化する利点
Flask-WTFを使わないChapter4-1~4-6まででは、フォームの処理において以下のような手順が必要でした:
- request.methodでGETとPOSTを分岐
- request.form.get("フィールド名")で値を取得
- 各値に対してバリデーションを手動で実装
- テンプレート内でフィールドのラベルや入力タグを手書き
- セキュリティのためのCSRF対策を実施(未紹介)
Flask-WTFを使えば、これらが一気に簡単になります。
| 従来のやり方(手動) | Flask-WTFを使ったやり方 | 
|---|---|
| フィールドの取得・バリデーションを手動 | form.validate_on_submit()で一括処理 | 
| CSRFトークンを自前で挿入 | 自動で含まれる | 
| HTMLフォームを自分で記述 | {{ form.フィールド名() }}で簡単表示 | 
Flask-WTFのインストール手順と基本構文
Flask-WTFをインストールしよう
まずは Flask-WTF ライブラリをインストールします。
ターミナル化コマンドプロンプトに以下のコードを打ち込みましょう。
pip install flask-wtf
Flask-WTF は、WTForms に加えて Flask との連携機能を提供してくれるライブラリです。
CSRFトークンの自動生成や、テンプレートでのフィールドレンダリングなど、初心者がつまづきやすいポイントを補ってくれます。
secret_keyの役割と設定方法
Flask-WTFを使うには、Flaskのアプリケーションに「秘密鍵(secret_key)」を設定する必要があります。
秘密鍵は「Webアプリの安全を守るための合言葉(パスワード)」として使用される文字列です。
秘密鍵を設定するとフォームの中に「CSRFトークン(不正アクセス防止用の特殊な文字列)」が自動的に埋め込まれます。
from flask import Flask app = Flask(__name__) # 秘密鍵の設定 app.secret_key = "これはCSRFトークンのために必要な秘密鍵"
この場合、「これはCSRFトークンのために必要な秘密鍵」という文字列が秘密鍵になります。
この例のように「適当な日本語の文字列」でも動きますが、推奨されるのは英数字や記号を混ぜたランダムな長い文字列です。
Flask-WTFを使うときは 必ず 設定しましょう。
FlaskFormクラスを使ったフォーム定義の例
次に、実際に使うフォームのクラスを作成します。
from flask_wtf import FlaskForm # Flask_wtfモジュールのFlaskFormクラスをインポート
from wtforms import StringField, SubmitField # 必要なフィールドクラスのインポート
from wtforms.validators import DataRequired  # 必要な組み込みバリデータのインポート
# FlaskFormを継承したNameFormクラスを定義
class NameForm(FlaskForm):
    name = StringField("名前", validators=[DataRequired()]) # 文字列入力フィールド
    submit = SubmitField("送信") # 送信ボタン- FlaskForm:すべてのフォームクラスの基底クラス
- StringField("名前"):テキスト入力欄の部品
- SubmitField("送信"):送信ボタン。
- DataRequired():入力必須を表すバリデーション
これでフォームの定義が完了です。
次はこれを使って、Webアプリとしてどう動かすのかを見ていきましょう。

Flask-WTF導入前後のコード比較で理解を深めよう
Flask-WTFを使用する場合と使用しない場合のコードを比較しましょう。
手動処理でフォームを実装する方法
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route("/hello", methods=["GET", "POST"])
def hello():
    name = ""
    if request.method == "POST":
        name = request.form.get("name")  # フォームから送られてきた値を取り出す
        if not name:
            error = "名前を入力してください。" # 必須バリデーション
    return render_template("hello.html", name=name)<form method="POST">
  <input type="text" name="name">  <!-- 入力欄 -->
  <input type="submit" value="送信"> <!-- ボタン -->
</form>
{% if name %}
<p>こんにちは、{{ name }}さん!</p>
{% endif %}- 値の取得やチェックを毎回自分で書かないといけない
- バリデーション(未入力など)も自分で作る必要がある
- セキュリティ(CSRF対策)も入っていない
Flask-WTFでフォームを簡単かつ安全に処理
from flask import Flask, render_template
from flask_wtf import FlaskForm				 # Flask_wtfモジュールのFlaskFormクラスをインポート
from wtforms import StringField, SubmitField # 必要なフィールドクラスをインポート
from wtforms.validators import DataRequired  # 必要な組み込みバリデータをインポート
app = Flask(__name__)
app.secret_key = "secret"   # CSRF保護のための秘密鍵設定
class NameForm(FlaskForm):								   # FlaskFormを継承したNameFormクラスを定義
    name = StringField("名前", validators=[DataRequired()]) # 名前の入力欄を定義(入力必須)
    submit = SubmitField("送信")							  # 送信ボタンを定義
@app.route("/hello", methods=["GET", "POST"]) # このURLにGETまたはPOSTリクエストが来たときに実行
def hello():
    form = NameForm()
    name = ""
    if form.validate_on_submit():  # POSTかつバリデーション成功時
        name = form.name.data      # 入力された値を取得
    return render_template("hello.html", form=form, name=name)<form method="POST">
  {{ form.csrf_token }}  <!-- CSRFトークンが自動で出力される -->
  {{ form.name.label }}  <!-- 「名前」というラベル -->
  {{ form.name() }}      <!-- 入力欄(自動で name="name" になる) -->
  {{ form.submit() }}    <!-- 送信ボタン -->
</form>
{% if name %}
<p>こんにちは、{{ name }}さん!</p>
{% endif %}| 改善点 | 解説 | 
|---|---|
| form.validate_on_submit() | 「POSTかつバリデーション成功時」の判定を1行で書ける | 
| form.name.data | 入力された値が自動で格納される | 
| form.name() | HTMLの入力タグが自動生成される(name属性なども含む) | 
| form.csrf_token | セキュリティ対策(CSRF)が自動挿入される | 
| form.submit() | HTMLの送信ボタンも自動で表示される | 
- フォーム定義もHTMLの表示も部品化されてスッキリ
- セキュリティも安心
- エラー処理や再表示にも強い
まとめ|Flask-WTFでフォーム開発をシンプル&安全に
Flask-WTFは、これまで学んできたフォーム処理・バリデーション・CSRF対策をすべてまとめて支援してくれる、非常に強力なツールです。
書くコードが減るだけでなく、セキュリティも高まり、保守性の高いアプリが作れるようになります。
「フォームの扱いが大変そう…」と感じていた人も、Flask-WTFを使えばスッキリ書けて、理解しやすくなるはずです。
- サイト改善アンケート|1分だけ、ご意見をお聞かせください
- 
本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。 
 そのため、ご利用者のみなさまの「プログラミングを学習する理由」などをアンケート形式でお伺いしています。ご協力いただけますと幸いです。 アンケート
練習問題:Flask-WTFでCSRF付きのフォームを作ってみよう

Flask-WTFを使うことで、Flask上でフォームを簡単かつ安全に扱うことができます。
この問題では、好きなフルーツの名前をユーザーに入力してもらい、それを画面上に表示するWebアプリを作成してください。
フォームにはバリデーション(未入力エラー)をつけ、送信後は「〇〇は美味しそうですね!」という日本語のメッセージを表示するようにします。
テンプレートファイル(HTML)は↓↓のコードを使用し、アプリファイル(Python)を作成してください。
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>フルーツフォーム</title>
</head>
<body>
  <h1>好きなフルーツを教えてください</h1>
  <!-- フォーム開始。POSTメソッドで送信 -->
  <form method="POST">
    {{ form.csrf_token }}  <!-- CSRF対策トークン(Flask-WTFが自動で挿入) -->
    <p>
      {{ form.fruit_name.label }}<br>  <!-- ラベル表示 -->
      {{ form.fruit_name(size=30) }}   <!-- 入力フィールドのHTML表示 -->
    </p>
    <p>
      {{ form.submit() }}  <!-- 送信ボタンのHTML出力 -->
    </p>
  </form>
  <!-- 結果があれば表示 -->
  {% if result %}
    <p><strong>{{ result }}</strong></p>
  {% endif %}
</body>
</html>この問題の要件
以下の要件に従ってコードを完成させてください。
以下の条件をすべて満たすPythonファイル(app.py)を作成してください。
- Flask-WTFのフォームクラスを FruitFormという名前で作成すること。
- フォームには以下の2つの項目を含めること:
- fruit_name:入力必須のテキスト入力欄
- submit:送信ボタン
 
- CSRFトークン保護を設定すること。
- フォームの送信が成功した場合、入力されたフルーツ名に対して「〇〇は美味しそうですね!」というメッセージを作成し、テンプレートへ渡すこと。
- form.validate_on_submit()を使ってバリデーションとPOST送信チェックを行うこと。
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
- ヒント:コードの構成を見る
- 
正解のコードは上から順に以下のような構成となっています。 1:必要なライブラリをすべてインポート 
 → Flask本体のほか、Flask-WTFとWTForms関連の部品も読み込みます。2:Flaskアプリの本体を作成し、CSRF対策のための「secret_key」を設定 
 → フォームを安全に使うために必要な準備です。3:「FruitForm」という名前のフォームクラスを定義 
 → この中で、テキスト入力欄(フルーツ名)と送信ボタンを定義します。
 → 入力は必須にしたいため、バリデーションの指定も行います。4:「/fruit」というURLにアクセスしたときにフォームを表示する関数を定義 
 → この関数では、フォームのオブジェクトを作り、テンプレートに渡す準備をします。5:フォームが送信されたかどうか、そして入力内容が正しいかをチェック 
 → 条件を満たす場合は、入力されたフルーツ名を取り出し、表示用のメッセージを作ります。6:フォームオブジェクトとメッセージをテンプレートに渡して表示 
 → 表示のためにrender_template()を使い、テンプレートファイル(fruit.html)に情報を渡します。7:このPythonファイルが直接実行されたときだけアプリが起動するように設定 
 → アプリのエントリーポイント(if name == “main”:)を忘れずに書きましょう。
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
正解コード
例えば、以下のようなプログラムが考えられます。
- 正解コード
- 
from flask import Flask, render_template from flask_wtf import FlaskForm # Flask-WTFの基本クラス from wtforms import StringField, SubmitField # 入力欄とボタン from wtforms.validators import DataRequired # 入力必須のバリデータ app = Flask(__name__) app.secret_key = "これはCSRF対策のために必要な秘密鍵です" # フォームクラスの定義 class FruitForm(FlaskForm): # フルーツ名を入力する欄。空欄禁止(DataRequired)バリデーション付き fruit_name = StringField("好きなフルーツの名前", validators=[DataRequired()]) # 送信ボタン submit = SubmitField("送信する") # フォームを表示・処理するルート @app.route("/fruit", methods=["GET", "POST"]) def fruit(): form = FruitForm() result = None # フォームが送信され、バリデーションが成功したときの処理 if form.validate_on_submit(): # 入力されたフルーツ名を取り出す fruit_name = form.fruit_name.data # 結果メッセージを作成 result = f"{fruit_name}は美味しそうですね!" # フォームと結果メッセージをテンプレートに渡す return render_template("fruit.html", form=form, result=result) # このファイルが直接実行されたときだけアプリを起動 if __name__ == "__main__": app.run(debug=True)
正解コードの詳細解説
正解コードをブロックごとに分割して解説します。
- 正解コードの詳細解説
- 
必要なライブラリのインポートfrom flask import Flask, render_template from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired ここでは、Flaskアプリを作成するために必要なライブラリを読み込んでいます。 - DataRequired:入力必須(空欄禁止)のバリデーションルール。
- Flask:Webアプリ本体を作るためのクラス。
- render_template:テンプレート(HTML)を表示するための関数。
- FlaskForm:Flask-WTFでフォームを使うときに必要な基本クラス。
- StringField:テキスト入力用のフォーム部品。
- SubmitField:送信ボタンの部品。
 Flaskアプリ本体の作成とセキュリティ設定app = Flask(__name__) app.secret_key = "これはCSRF対策のために必要な秘密鍵です" - app = Flask(__name__):Flaskアプリケーションの本体を作り、変数- appに保存。
- secret_key:CSRF対策に必要な暗号鍵。これがあることで不正な送信を防ぐことができる。
 フォームのクラスを作成class FruitForm(FlaskForm): fruit_name = StringField("好きなフルーツの名前", validators=[DataRequired()]) submit = SubmitField("送信する")Flask-WTFで使うフォームを定義しています。 - submit:送信ボタン。ラベルは「送信する」。
- FruitForm:フォームの名前(自由に決められるがわかりやすく)。
- fruit_name:ユーザーが入力する「好きなフルーツ名」の欄。ラベルは「好きなフルーツの名前」。
- validators=[DataRequired()]:入力を必須にする設定。未入力のまま送信しようとするとエラーになる。
 ルーティングとフォーム処理@app.route("/fruit", methods=["GET", "POST"]) def fruit(): form = FruitForm() result = None if form.validate_on_submit(): fruit_name = form.fruit_name.data result = f"{fruit_name}は美味しそうですね!" return render_template("fruit.html", form=form, result=result)この部分では、 /fruitにアクセスされたときの動きを定義しています。- render_template():HTMLファイルを表示し、その中にフォームと結果を渡す。
- @app.route("/fruit", methods=["GET", "POST"]):フォームを表示&送信処理をするURLを設定。
- form = FruitForm():作成したフォームクラスを使ってフォームのインスタンスを作成。
- form.validate_on_submit():ページが送信された(POST)ことと「空欄禁止」を満たしていることを同時にチェック
- form.fruit_name.data:ユーザーが入力したフルーツ名を取得。
- result:表示用のメッセージを作成。
 Flaskアプリの起動設定if __name__ == "__main__": app.run(debug=True)- if __name__ == "__main__"::このファイルが直接実行されたときだけ、下の処理を実行する。
- app.run(debug=True):アプリを起動。- debug=Trueにすると、コードを変更したときに自動で再起動してくれる。
 
FAQ|Flask-WTFの導入と活用に関するよくある質問
- Q1. Flask-WTFの導入時に「secret_key」は必ず必要ですか?
- 
はい、Flask-WTFではCSRF保護機能が標準で有効になっており、そのトークンの生成に「secret_key」が必須です。これが設定されていないと、フォームは正しく動作しません。 
- Q2. Flask-WTFのフォームクラスは複数作っても問題ありませんか?
- 
問題ありません。用途ごとに異なるフォームクラスを定義することで、アプリの構造が整理され、保守性も高まります。各クラスはFlaskFormを継承して独立して動作します。 
- Q3. Flask-WTFを使うとフォームのバリデーションエラーは自動で表示されますか?
- 
いいえ、自動では表示されません。テンプレート側で {{ form.field.errors }}を使って、必要な位置にエラーメッセージを表示させる必要があります。






