序章

テキストフィールドやテキスト領域などの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リストに保存されているコースを表示するためのページがあり、インデックスページには、コースのタイトル、説明、価格、可用性、およびレベル(初級、中級、または上級)を入力するためのフォームがあります。

前提条件

ステップ1—FlaskとFlask-WTFのインストール

このステップでは、FlaskとFlask-WTFをインストールします。これにより、WTFormsライブラリも自動的にインストールされます。

仮想環境をアクティブにして、 pip FlaskとFlask-WTFをインストールするには:

  1. pip install Flask Flask-WTF

インストールが正常に完了すると、出力の最後に次のような行が表示されます。

Output
Successfully 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 ディレクトリ。 このファイルには、アプリケーションで必要なフォームが含まれています。

  1. nano forms.py

このファイルには、Webフォームを表すクラスが含まれます。 上部に次のインポートを追加します。

フラスコ_app/forms.py
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ライブラリからインポートします。

行で from wtforms.validators import InputRequired, Length、フィールドで使用するバリデーターをインポートして、ユーザーが有効なデータを送信することを確認します。 InputRequired は、入力が提供されていることを確認するために使用するバリデーターです。 Length は、文字列の長さを検証して、文字列の最小文字数を確認するためのものです。特定の長さを超えない。

次に、次のclassimport ステートメント:

フラスコ_app/forms.py

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 ディレクトリ:

  1. nano app.py

このファイルは、Flaskから必要なクラスとヘルパーをインポートします。 CourseForm から forms.py ファイル。 コースのリストを作成し、フォームをインスタンス化してテンプレートファイルに渡します。 次のコードをに追加します app.py:

フラスコ_app/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() ビュー機能。 両方を受け入れます GETPOST 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、これは他のテンプレートの基本テンプレートになります。

  1. mkdir templates
  2. nano templates/base.html

内に次のコードを追加します base.html ナビゲーションバーとコンテンツブロックを含むベーステンプレートを作成するファイル:

フラスコ_app/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="#">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 ファイル:

  1. nano templates/index.html

このファイルには、渡したWebフォームが含まれます。 index.html 経由のテンプレート form 変数。 次のコードを追加します。

フラスコ_app/templates / index.html
{% 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) }}、およびパラメータを使用して説明テキスト領域の行と列の数を設定します rowscols HTMLで通常行うのと同じ方法です。 同じメソッドを使用して、追加のHTML属性を次のようなフィールドに渡すことができます。 class CSSクラスを設定するための属性。

構文を使用して検証エラーをチェックします if form.field.errors. フィールドにエラーがある場合は、 for ループして、フィールドの下のリストに表示します。

あなたの中に flask_app 仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py この場合)を使用して FLASK_APP 環境変数。 次に、 FLASK_ENV 環境変数から development アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します(Windowsでは、 set それ以外の export):

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

次に、アプリケーションを実行します。

  1. flask run

開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。

http://127.0.0.1:5000/

インデックスページにWebフォームが表示されます。

タイトルを入力せずにフォームを送信してみてください。 タイトルが必要であることを通知するエラーメッセージが表示されます。 無効なデータ(10文字未満の短いタイトルや200文字を超える説明など)を送信してフォームを試して、他のエラーメッセージを確認してください。

フォームの送信を処理するコードがないため、これまでのところ、フォームに有効なデータを入力しても何も起こりません。 そのためのコードは後で追加します。

今のところ、リストにあるコースを表示するページが必要です。 後で、Webフォームデータを処理すると、リストに新しいコースが追加され、ユーザーをコースページにリダイレクトして、追加された新しいコースを確認します。

開発サーバーを実行したままにして、別のターミナルウィンドウを開きます。

次に、開く app.py コースルートを追加するには:

  1. nano app.py

ファイルの最後に次のルートを追加します。

フラスコ_app/app.py
# ...

@app.route('/courses/')
def courses():
    return render_template('courses.html', courses_list=courses_list)

ファイルを保存して閉じます。

このルートは、と呼ばれるテンプレートをレンダリングします courses.html、それを渡す courses_list リスト。

次に、を作成します courses.html コースを表示するためのテンプレート:

  1. nano templates/courses.html

次のコードを追加します。

フラスコ_app/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 ナビゲーションバーのコースページへのリンクを追加するには:

  1. nano templates/base.html

次のように編集します。

フラスコ_app/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() 関数:

  1. nano app.py

編集します index() 次のように見える関数:

フラスコ_app/app.py
# ...
@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サイトを作成する方法シリーズの他のチュートリアルをご覧ください。