
目標
- Flaskのルーティングを利用した小規模アプリを作成できる。
- テンプレートに処理の呼び出しを定義する。
- フォームを利用できる。
- リダイレクトを利用できる。
- リクエストパラメータを利用できる。
Flaskのルーティングを利用した小規模アプリの作成
テンプレートに処理の呼び出しを定義する
前回の記事(Part.5)では次のページ遷移を行えるシステムを作成しました。
- 商品管理ページと商品一覧ページは双方向へ遷移可能。
- 商品管理ページと商品追加ページは双方向へ遷移可能。
- 商品一覧ページと商品追加ページは双方向へ遷移可能。
- 商品追加を行った後は商品一覧ページへリダイレクトされる。

テンプレートファイルの内容(アンカータグへのurl_for() 関数の設定)
ここでは以下の3つのテンプレートを「templates」ディレクトリに準備しました。
- 商品管理ページ…manage_products.html
- 商品一覧ページ…products.html
- 商品追加ページ…add_product.html
この時、テンプレートでは、ページ遷移を行うために、アンカータグ(aタグ)の href属性 に url_for()関数を利用しました。
この、Flaskの url_for() 関数は、Flaskのルーティングで定義された関数(エンドポイント)に対応するURLを生成するためのものでした。アンカータグの href属性 で利用される場合は、この部分が適切なURLとして設定されます。
例えば、manage_products.html 内の href=”{{ url_for(‘product_list’) }}” の場合、Flaskのルーティングで定義されたエンドポイントに基づき、適切なURLが生成されることになり、今回の場合、app.pyファイル内で関数名が product_list でそれに対応するURLは、 /products なので、レンダリングされた時に、href=”/products” としてHTMLファイルで生成されることになります。
レンダリングされたファイルで、このタグをクリックするとFlaskのルーティングに従って、該当するproduct_list()関数が実行されることになります。FlaskのルーティングでRuleの部分がURLに該当します。

Flaskのルーティングを確認できる flask routes コマンド
Flaskのルーティングは次のコマンドで確認ができます。
環境変数を有効化して「flask routes」コマンドを実行します。
C:\Users\user\Desktop\FlaskProj>.venv\Scripts\activate
# 仮想環境が有効化されます。
(venv) C:\Users\user\Desktop\FlaskProj>flask routes
次のような表が確認でいます。

manage_products.html(14,15行目)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品管理</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>商品管理ページ</h1>
<ul>
<li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧</a></li>
<li><a href="{{ url_for('add_product') }}" class="button-link">商品追加</a></li>
</ul>
</body>
</html>
add_product.html(15,16行目)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品追加</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>商品追加ページ</h1>
<ul>
<li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧に戻る</a></li>
<li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
</ul>
<h1>商品追加フォーム</h1>
<form method="POST" action="{{ url_for('add_product') }}">
<label for="name">商品名</label>
<input type="text" id="name" name="name" placeholder="商品名を入力" required>
<label for="price">価格</label>
<input type="number" id="price" name="price" placeholder="価格を入力" required>
<input type="submit" value="商品を追加する">
</form>
</body>
</html>
products.html(14,15行目)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品一覧</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>商品一覧ページ</h1>
<ul>
<li><a href="{{ url_for('add_product') }}" class="button-link">商品を追加する</a></li>
<li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
</ul>
<h1>商品一覧</h1>
<ul>
{% for product in products %}
<li>{{ product.name }} : ¥{{ "{:,}".format(product.price) }}</li>
{% endfor %}
</ul>
</body>
</html>
フォームを利用できる
フォームに入力された値は、リクエスト(データの取得(≒ページの要求))と一緒にリクエストパラメーターとしてサーバー側に送られます。

送られた値はrequest.formオブジェクトに格納されます。

HTMLファイルとrequest.formオブジェクトから取り出した値をレンダリングしてユーザーにレスポンスします。

次のコードは、商品名と価格を入力し、POSTリクエストを/add_productに送信するためのものです。ここで、入力した商品名と価格は、サーバーに送信され、データベース(今回はpythonの辞書)に追加されます。
このフォームの、重要なポイントは、action=”{{ url_for(‘add_product’) }}”によって、適切なURLにデータが送信されること、そしてPOSTメソッドを使用してデータがサーバーに送信され、処理される点です。
商品の追加機能を実現するための重要なポイントにはつぎのものがあります。
method=”POST”(21行目)
フォームの送信方法がPOSTで指定されています(※指定しなければ送信方法はGETとなります)。基本的に、フォームを利用してデータを送信する場合はPOSTメソッドを使用します。
action=”{{ url_for(‘add_product’) }}”
action属性には、url_for(‘add_product’)が指定されています。url_for()は、Flaskのルートに定義されたエンドポイントadd_productに対応するURLを生成します。この場合、@app.route(“/add_product”, methods=[“GET”, “POST”])で定義されたadd_product関数が対応するURLとなります。
つまり、このフォームは/add_productにPOSTリクエストを送信し、商品追加の処理が行われることになります。
フォームフィールド(商品名と価格)
ユーザーから商品名と価格を入力してもらうための入力ボックスのことです。
required属性がついているため、これらのフィールドは必須入力項目となり、空のままフォームを送信することができません。
name属性
フォームで送信するデータの「キー名」を定義します。具体的には、フォームで送信するデータはname属性で決めた「キー名」と入力されたvalue「値」を、「キー名:値」のように、ひとつの対として送信します(例:address:東京都新宿区)。
Flaskでは、フォームから送信されたデータはrequest.formオブジェクトを通じてアクセスできます。例:address = request.form[‘address’]
type属性 の “submit”
フォームを送信するためのボタンです。ボタンをクリックすると、フォームのデータ(商品名と価格)がサーバーに送信されます。
add_product.html(21から29行目)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品追加</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>商品追加ページ</h1>
<ul>
<li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧に戻る</a></li>
<li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
</ul>
<h1>商品追加フォーム</h1>
<form method="POST" action="{{ url_for('add_product') }}">
<label for="name">商品名</label>
<input type="text" id="name" name="name" placeholder="商品名を入力" required>
<label for="price">価格</label>
<input type="number" id="price" name="price" placeholder="価格を入力" required>
<input type="submit" value="商品を追加する">
</form>
</body>
</html>
リダイレクトを利用できる
Flaskでリダイレクトを行う場合はredirectを利用します。redirectは、クライアントに別のページへの移動を指示するレスポンスを返します。つまり、ユーザーを新しいURLに自動的に移動させるために使用されます。Flaskでは、次のように使います。
return redirect(url_for("product_list"))
この行が意味することは、ユーザーが「商品追加フォーム」を送信した後に、product_listというエンドポイント(URL)にリダイレクトされるということです。リダイレクトによって、ユーザーは商品一覧ページに自動的に移動します。
リクエストパラメータを利用できる。
リクエストパラメータとは、ユーザーがフォームに入力したデータです。Flaskでは、requestオブジェクトを使ってリクエストパラメータにアクセスできます。例えば、ユーザーが「商品名」と「価格」を入力してフォームを送信した場合、そのデータはrequest.formを使って取得できます。
次のコードでは、ユーザーがフォームで送信した「商品名」と「価格」を取得しています
name = request.form["name"]
price = int(request.form["price"])
- request.form[“name”]で、nameという名前のフォームフィールドのデータ(商品名)を取得します。
- request.form[“price”]で、priceという名前のフォームフィールドのデータ(価格)を取得します。
POSTリクエストの処理の流れ
フォーム送信(POSTリクエスト)
ユーザーが商品名と価格を入力し、フォームを送信すると、POSTメソッドで/add_productにリクエストが送信されます。このとき、商品名と価格のデータがrequest.formに含まれることになります。
データの処理
サーバー側では、add_product関数内で次の処理が行われます。
- request.form[“name”]で商品名を取得
- request.form[“price”]で価格を取得し、int()で数値に変換
- productsリストに新しい商品を追加
商品は、products.append({“id”: new_id, “name”: name, “price”: price})でリストに追加されます。新しい商品のidは、既存の商品の数を基に計算されます。
リダイレクト(redirect)
商品が追加されると、redirect(url_for(“product_list”))が実行され、ユーザーは商品一覧ページ(/products)にリダイレクトされます。リダイレクトは、URLの変更を伴い、ブラウザに新しいURLを表示させるために使用されます。
render_template(“products.html”, products=products)
render_template(“products.html”, products=products)のproducts=products部分は、FlaskのテンプレートエンジンであるJinja2に対してデータを渡すための部分です。この構文は、Pythonの変数productsをテンプレート内で使用できるようにするために使います。
render_template("products.html", products=products)
app.pyファイル
from flask import Flask, redirect, render_template, request, url_for
app = Flask(__name__)
# 商品リスト
products = [
{"id": 1, "name": "オレンジジュース", "price": 140},
{"id": 2, "name": "アップルジュース", "price": 150},
{"id": 3, "name": "牛乳", "price": 180},
]
@app.route("/")
def index():
return "Top page"
@app.route("/products")
def product_list():
return render_template("products.html", products=products)
@app.route("/add_product", methods=["GET", "POST"])
def add_product():
if request.method == "POST":
# フォームから送られたデータを取得
name = request.form["name"]
price = int(request.form["price"])
# 新しい商品を追加
new_id = len(products) + 1
products.append({"id": new_id, "name": name, "price": price})
# 商品一覧ページにリダイレクト
return redirect(url_for("product_list"))
return render_template("add_product.html")
@app.route("/manage_products")
def manage_products():
# 商品管理ページを表示
return render_template("manage_products.html")
if __name__ == "__main__":
app.run(debug=True)
今回は以上になります。

ブックマークのすすめ
「ほわほわぶろぐ」を常に検索するのが面倒だという方はブックマークをお勧めします。ブックマークの設定は別記事にて掲載しています。

