Flask-WTFでWebフォームを使用および検証する方法
序章
テキストフィールドやテキスト領域などのWebフォームを使用すると、ユーザーは、アプリケーションがアクションを実行するために使用するドロップダウンまたはラジオボタンであるかどうかにかかわらず、アプリケーションにデータを送信したり、大量のテキストをに送信したりすることができます。処理または表示されます。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーがページに新しいコンテンツを追加できるボックスをユーザーに提供できます。
Flask は、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 Flaskで安全かつ柔軟な方法でWebフォームをレンダリングおよび検証するには、 Flask-WTF を使用します。これは、FlaskでWTFormsライブラリを使用するのに役立つFlask拡張機能です。応用。
WTForms は、柔軟なWebフォームレンダリングを提供するPythonライブラリです。 これを使用して、テキストフィールド、テキスト領域、パスワードフィールド、ラジオボタンなどをレンダリングできます。 WTFormsは、さまざまなバリデーターを使用した強力なデータ検証も提供します。これにより、ユーザーが送信するデータが、定義した特定の基準を満たしていることが検証されます。 たとえば、必須フィールドがある場合、ユーザーが送信するデータが提供されていること、または特定の長さであることを確認できます。
WTFormsはまた、CSRFトークンを使用して、 CSRF攻撃からの保護を提供します。これは、攻撃者がユーザーが認証されたWebアプリケーションで不要なアクションを実行できるようにする攻撃です。 CSRF攻撃が成功すると、ユーザーは、銀行アプリケーションで攻撃者の銀行口座に資金を送金したり、ユーザーの電子メールアドレスを変更したりするなど、状態を変更する要求を実行するように強制される可能性があります。 被害者が管理者アカウントである場合、CSRFはWebアプリケーション全体を危険にさらす可能性があります。
このチュートリアルでは、Flask-WTFを使用してWebフォームをレンダリングおよび検証する方法を示す小さなWebアプリケーションを作成します。 アプリケーションには、Pythonリストに保存されているコースを表示するためのページがあり、インデックスページには、コースのタイトル、説明、価格、可用性、およびレベル(初級、中級、または上級)を入力するためのフォームがあります。
前提条件
-
ローカルのPython3プログラミング環境。 Python3シリーズのローカルプログラミング環境をインストールおよびセットアップする方法」のオペレーティングシステムのチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリを呼び出します
flask_app
. -
ルート、ビュー関数、テンプレートなどの基本的なFlaskの概念の理解。 Flaskに慣れていない場合は、FlaskとPythonを使用して最初のWebアプリケーションを作成する方法およびFlaskアプリケーションでテンプレートを使用する方法を確認してください。
-
基本的なHTMLの概念の理解。 背景知識については、HTMLを使用してWebサイトを構築する方法チュートリアルシリーズを確認できます。
-
(オプション)Flaskでの基本的なWebフォームの使用法の理解。 FlaskアプリケーションでWebフォームを使用する方法を参照してください。
ステップ1—FlaskとFlask-WTFのインストール
このステップでは、FlaskとFlask-WTFをインストールします。これにより、WTFormsライブラリも自動的にインストールされます。
仮想環境をアクティブにして、 pip
FlaskとFlask-WTFをインストールするには:
- pip install Flask Flask-WTF
インストールが正常に完了すると、出力の最後に次のような行が表示されます。
OutputSuccessfully installed Flask-2.0.2 Flask-WTF-1.0.0 Jinja2-3.0.3 MarkupSafe-2.0.1 WTForms-3.0.0 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1
ご覧のとおり、WTFormsライブラリもFlask-WTFパッケージの依存関係としてインストールされました。 残りのパッケージはFlaskの依存関係です。
必要なPythonパッケージをインストールしたので、次にWebフォームを設定します。
ステップ2—フォームの設定
このステップでは、WTFormsライブラリからインポートするフィールドと検証ツールを使用してWebフォームを設定します。
次のフィールドを設定します。
- タイトル:コースタイトルのテキスト入力フィールド。
- 説明:コース説明のテキスト領域フィールド。
- 価格:コースの価格の整数フィールド。
- レベル:初級、中級、上級の3つの選択肢があるコースレベルの無線フィールド。
- 利用可能:コースが現在利用可能かどうかを示すチェックボックスフィールド。
まず、という新しいファイルを開きます forms.py
あなたの中で flask_app
ディレクトリ。 このファイルには、アプリケーションで必要なフォームが含まれています。
- nano forms.py
このファイルには、Webフォームを表すクラスが含まれます。 上部に次のインポートを追加します。
from flask_wtf import FlaskForm
from wtforms import (StringField, TextAreaField, IntegerField, BooleanField,
RadioField)
from wtforms.validators import InputRequired, Length
Webフォームを作成するには、のサブクラスを作成します FlaskForm
からインポートする基本クラス flask_wtf
パッケージ。 また、フォームで使用するフィールドを指定する必要があります。このフィールドは、フォームからインポートします。 wtforms
パッケージ。
次のフィールドをWTFormsライブラリからインポートします。
- StringField :テキスト入力。
- TextAreaField :テキスト領域フィールド。
- IntegerField :整数のフィールド。
- BooleanField :チェックボックスフィールド。
- RadioField :ユーザーが選択できるラジオボタンのリストを表示するためのフィールド。
行で from wtforms.validators import InputRequired, Length
、フィールドで使用するバリデーターをインポートして、ユーザーが有効なデータを送信することを確認します。 InputRequired は、入力が提供されていることを確認するために使用するバリデーターです。 Length は、文字列の長さを検証して、文字列の最小文字数を確認するためのものです。特定の長さを超えない。
次に、次のclassを import
ステートメント:
class CourseForm(FlaskForm):
title = StringField('Title', validators=[InputRequired(),
Length(min=10, max=100)])
description = TextAreaField('Course Description',
validators=[InputRequired(),
Length(max=200)])
price = IntegerField('Price', validators=[InputRequired()])
level = RadioField('Level',
choices=['Beginner', 'Intermediate', 'Advanced'],
validators=[InputRequired()])
available = BooleanField('Available', default='checked')
ファイルを保存して閉じます。
これで CourseForm
クラス、あなたはから継承します FlaskForm
以前にインポートした基本クラス。 WTFormsライブラリからインポートしたフォームフィールドを使用して、フォームフィールドのコレクションをクラス変数として定義します。 フィールドをインスタンス化する場合、最初の引数はフィールドのラベルです。
からインポートしたバリデーターのリストを渡すことにより、各フィールドのバリデーターを定義します。 wtforms.validators
モジュール。 たとえば、タイトルフィールドには文字列があります 'Title'
ラベルとして、および2つのバリデーター:
InputRequired
:フィールドが空であってはならないことを示します。Length
:2つの引数を取ります。min
に設定されています10
タイトルの長さが10文字以上であることを確認し、max
に設定されています100
100文字を超えないようにします。
説明テキスト領域フィールドには、 InputRequired
バリデーターと Length
バリデーター max
パラメータをに設定 200
、値なし min
パラメータ。これは、200文字を超えないことが唯一の要件であることを意味します。
同様に、と呼ばれるコースの価格に必要な整数フィールドを定義します price
.
The level
フィールドは、複数の選択肢がある無線フィールドです。 Pythonリストで選択肢を定義し、それを choices
パラメータ。 また、必要に応じてフィールドを定義します。 InputRequired
バリデーター。
The available
フィールドはチェックボックスフィールドです。 デフォルトを設定します 'checked'
に渡すことによって値 default
パラメータ。 これは、ユーザーがチェックを外さない限り、新しいコースを追加するときにチェックボックスがオンになることを意味します。つまり、コースはデフォルトで利用可能です。
WTFormsライブラリの使用方法の詳細については、WTFormsドキュメントのクラッシュコースページを参照してください。 その他のフィールドについてはフィールドページを、フォームデータを検証するためのその他のバリデーターについてはバリデーターページを参照してください。
Webフォームを forms.py
ファイル。 次に、Flaskアプリケーションを作成し、このフォームをインポートして、そのフィールドをインデックスページに表示します。 また、別のページにコースのリストを表示します。
ステップ3—Webフォームとコースを表示する
このステップでは、Flaskアプリケーションを作成し、前のステップで作成したWebフォームをインデックスページに表示し、コースのリストとその上にコースを表示するためのページも作成します。
プログラミング環境をアクティブにしてFlaskをインストールした状態で、次のファイルを開きます。 app.py
あなたの中で編集するため flask_app
ディレクトリ:
- nano app.py
このファイルは、Flaskから必要なクラスとヘルパーをインポートします。 CourseForm
から forms.py
ファイル。 コースのリストを作成し、フォームをインスタンス化してテンプレートファイルに渡します。 次のコードをに追加します app.py
:
from flask import Flask, render_template, redirect, url_for
from forms import CourseForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'
courses_list = [{
'title': 'Python 101',
'description': 'Learn Python basics',
'price': 34,
'available': True,
'level': 'Beginner'
}]
@app.route('/', methods=('GET', 'POST'))
def index():
form = CourseForm()
return render_template('index.html', form=form)
ファイルを保存して閉じます。
ここでは、Flaskから以下をインポートします。
- The
Flask
Flaskアプリケーションインスタンスを作成するためのクラス。 - The
render_template()
インデックステンプレートをレンダリングする関数。 - The
redirect()
新しいコースが追加されたら、ユーザーをコースページにリダイレクトする機能。 - The
url_for()
URLを構築するための関数。
まず、インポートします CourseForm()
からのクラス forms.py
ファイルを作成し、Flaskアプリケーションインスタンスを作成します。 app
.
Webフォームを保護するためにCSRFトークンを生成するときに使用するWTFormsの秘密鍵構成を設定します。 秘密鍵は長いランダムな文字列である必要があります。 秘密鍵を取得する方法の詳細については、FlaskアプリケーションでWebフォームを使用する方法のステップ3を参照してください。
次に、と呼ばれる辞書のリストを作成します courses_list
、現在、1つの辞書とタイトルのサンプルコースがあります 'Python 101'
. ここでは、デモの目的でPythonリストをデータストアとして使用します。 実際のシナリオでは、SQLiteなどのデータベースを使用します。 データベースを使用してコースのデータを保存する方法については、FlaskアプリケーションでSQLiteデータベースを使用する方法を参照してください。
あなたは /
を使用したメインルート app.route()
上のデコレータ index()
ビュー機能。 両方を受け入れます GET
と POST
HTTPメソッドの methods
パラメータ。 GETメソッドはデータを取得するためのものであり、POSTリクエストは、たとえばWebフォームを介してサーバーにデータを送信するためのものです。 詳細については、FlaskアプリケーションでWebフォームを使用する方法を参照してください。
あなたはインスタンス化します CourseForm()
Webフォームを表し、インスタンスをという変数に保存するクラス form
. 次に、に電話を返します render_template()
関数、それに呼ばれるテンプレートファイルを渡します index.html
およびフォームインスタンス。
インデックスページにWebフォームを表示するには、最初にベーステンプレートを作成します。このテンプレートには、コードの繰り返しを避けるために他のテンプレートでも使用されるすべての基本的なHTMLコードが含まれます。 次に、を作成します index.html
レンダリングしたテンプレートファイル index()
関数。 テンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。
作成する templates
あなたのフォルダ flask_app
Flaskがテンプレートを検索するディレクトリ。次に、というテンプレートファイルを開きます。 base.html
、これは他のテンプレートの基本テンプレートになります。
- mkdir templates
- nano templates/base.html
内に次のコードを追加します base.html
ナビゲーションバーとコンテンツブロックを含むベーステンプレートを作成するファイル:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %} - FlaskApp</title>
<style>
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">FlaskApp</a>
<a href="#">About</a>
</nav>
<hr>
<div class="content">
{% block content %} {% endblock %}
</div>
</body>
</html>
この基本テンプレートには、他のテンプレートで再利用する必要があるすべてのHTMLボイラープレートが含まれています。 The title
各ページのタイトルを設定するためにブロックが置き換えられ、 content
ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには2つのリンクがあります。1つは、を使用するインデックスページ用です。 url_for()
リンクするヘルパー関数 index()
表示機能、およびアプリケーションに1つを含めることを選択した場合は、[バージョン情報]ページ用のもう1つ。
ファイルを保存して閉じます。
次に、というテンプレートを開きます index.html
. これは、で参照したテンプレートです。 app.py
ファイル:
- nano templates/index.html
このファイルには、渡したWebフォームが含まれます。 index.html
経由のテンプレート form
変数。 次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Add a New Course {% endblock %}</h1>
<form method="POST" action="/">
{{ form.csrf_token }}
<p>
{{ form.title.label }}
{{ form.title(size=20) }}
</p>
{% if form.title.errors %}
<ul class="errors">
{% for error in form.title.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>
{{ form.description.label }}
</p>
{{ form.description(rows=10, cols=50) }}
{% if form.description.errors %}
<ul class="errors">
{% for error in form.description.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>
{{ form.price.label }}
{{ form.price() }}
</p>
{% if form.price.errors %}
<ul class="errors">
{% for error in form.price.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>
{{ form.available() }} {{ form.available.label }}
</p>
{% if form.available.errors %}
<ul class="errors">
{% for error in form.available.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>
{{ form.level.label }}
{{ form.level() }}
</p>
{% if form.level.errors %}
<ul class="errors">
{% for error in form.level.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<p>
<input type="submit" value="Add">
</p>
</form>
{% endblock %}
ファイルを保存して閉じます。
基本テンプレートを拡張し、タイトルを設定します <h1>
鬼ごっこ。 次に、Webフォームフィールドを内部にレンダリングします <form>
タグ、メソッドをに設定 POST
とへのアクション /
インデックスページであるメインルート。 最初に、WTFormsが使用するCSRFトークンをレンダリングして、次の行を使用してフォームをCSRF攻撃から保護します。 {{ form.csrf_token }}
. このトークンは、残りのフォームデータとともにサーバーに送信されます。 フォームを保護するために、常にこのトークンをレンダリングすることを忘れないでください。
構文を使用して各フィールドをレンダリングします form.field()
構文を使用してラベルをレンダリングします form.field.label
. フィールドに引数を渡して、フィールドの表示方法を制御できます。 たとえば、タイトル入力フィールドのサイズをで設定します {{ form.title(size=20) }}
、およびパラメータを使用して説明テキスト領域の行と列の数を設定します rows
と cols
HTMLで通常行うのと同じ方法です。 同じメソッドを使用して、追加のHTML属性を次のようなフィールドに渡すことができます。 class
CSSクラスを設定するための属性。
構文を使用して検証エラーをチェックします if form.field.errors
. フィールドにエラーがある場合は、 for
ループして、フィールドの下のリストに表示します。
あなたの中に flask_app
仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py
この場合)を使用して FLASK_APP
環境変数。 次に、 FLASK_ENV
環境変数から development
アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します(Windowsでは、 set
それ以外の export
):
- export FLASK_APP=app
- export FLASK_ENV=development
次に、アプリケーションを実行します。
- flask run
開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。
http://127.0.0.1:5000/
インデックスページにWebフォームが表示されます。
タイトルを入力せずにフォームを送信してみてください。 タイトルが必要であることを通知するエラーメッセージが表示されます。 無効なデータ(10文字未満の短いタイトルや200文字を超える説明など)を送信してフォームを試して、他のエラーメッセージを確認してください。
フォームの送信を処理するコードがないため、これまでのところ、フォームに有効なデータを入力しても何も起こりません。 そのためのコードは後で追加します。
今のところ、リストにあるコースを表示するページが必要です。 後で、Webフォームデータを処理すると、リストに新しいコースが追加され、ユーザーをコースページにリダイレクトして、追加された新しいコースを確認します。
開発サーバーを実行したままにして、別のターミナルウィンドウを開きます。
次に、開く app.py
コースルートを追加するには:
- nano app.py
ファイルの最後に次のルートを追加します。
# ...
@app.route('/courses/')
def courses():
return render_template('courses.html', courses_list=courses_list)
ファイルを保存して閉じます。
このルートは、と呼ばれるテンプレートをレンダリングします courses.html
、それを渡す courses_list
リスト。
次に、を作成します courses.html
コースを表示するためのテンプレート:
- nano templates/courses.html
次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Courses {% endblock %}</h1>
<hr>
{% for course in courses_list %}
<h2> {{ course['title'] }} </h2>
<h4> {{ course['description'] }} </h4>
<p> {{ course['price'] }}$ </p>
<p><i>({{ course['level'] }})</i></p>
<p>Availability:
{% if course['available'] %}
Available
{% else %}
Not Available
{% endif %}</p>
<hr>
{% endfor %}
{% endblock %}
ファイルを保存して閉じます。
タイトルを設定し、のアイテムをループします courses_list
リスト。 タイトルを表示します <h2>
タグ、説明 <h4>
タグ、および価格とコースレベル <p>
鬼ごっこ。 条件を使用してコースが利用可能かどうかを確認します if course['available']
. コースが利用可能な場合は「利用可能」というテキストを表示し、利用できない場合は「利用不可」というテキストを表示します。
ブラウザを使用してコースページに移動します。
http://127.0.0.1:5000/courses/
これまでのコースリストにはコースが1つしかないため、1つのコースが表示されたページが表示されます。
次に、開く base.html
ナビゲーションバーのコースページへのリンクを追加するには:
- nano templates/base.html
次のように編集します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %} - FlaskApp</title>
<style>
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">FlaskApp</a>
<a href="{{ url_for('courses') }}">Courses</a>
<a href="#">About</a>
</nav>
<hr>
<div class="content">
{% block content %} {% endblock %}
</div>
</body>
</html>
ファイルを保存して閉じます。
インデックスページを更新すると、ナビゲーションバーに新しいCoursesリンクが表示されます。
アプリケーションに必要なページを作成しました。新しいコースを追加するためのWebフォームを備えたインデックスページと、リストにあるコースを表示するためのページです。
アプリケーションを機能させるには、ユーザーがWebフォームデータを送信するときに、それを検証してコースリストに追加することにより、Webフォームデータを処理する必要があります。 次にこれを行います。
ステップ4—フォームデータへのアクセス
このステップでは、ユーザーが送信したデータにアクセスして検証し、コースのリストに追加します。
開ける app.py
内部のWebフォームデータを処理するためのコードを追加するには index()
関数:
- nano app.py
編集します index()
次のように見える関数:
# ...
@app.route('/', methods=('GET', 'POST'))
def index():
form = CourseForm()
if form.validate_on_submit():
courses_list.append({'title': form.title.data,
'description': form.description.data,
'price': form.price.data,
'available': form.available.data,
'level': form.level.data
})
return redirect(url_for('courses'))
return render_template('index.html', form=form)
ファイルを保存して閉じます。 ここでは、 validate_on_submit()
上のメソッド form
オブジェクト。リクエストがPOSTリクエストであることを確認し、各フィールドに設定したバリデーターを実行します。 少なくとも1つのバリデーターがエラーを返す場合、条件は次のようになります。 False
、および各エラーは、それを引き起こしたフィールドの下に表示されます。
送信されたフォームデータが有効な場合、条件は次のとおりです。 True
、および以下のコード if
ステートメントが実行されます。 コース辞書を作成し、 append
新しいコースをに追加する方法 courses_list
リスト。 構文を使用して各フィールドの値にアクセスします form.field.data
. 新しいコース辞書をコースリストに追加した後、ユーザーをにリダイレクトします Courses
ページ。
開発サーバーが実行されている状態で、インデックスページにアクセスします。
http://127.0.0.1:5000/
フォームに有効なデータを入力して送信します。 にリダイレクトされます Courses
ページをクリックすると、新しいコースが表示されます。
結論
Flask-WTF拡張機能とWTFormsライブラリを使用して作成したWebフォームを持つFlaskアプリケーションを作成しました。 フォームには、ユーザーからデータを受け取り、特別なWTFormsバリデーターを使用してデータを検証し、データストアに追加するためのいくつかのタイプのフィールドがあります。
Flaskの詳細については、Flaskを使用してWebサイトを作成する方法シリーズの他のチュートリアルをご覧ください。