Flaskは、UIを持つアプリを実装するデザインパターンとしてMVTモデル(Model/View/Template)を採用してます。
- Model:ロジックを担当
- View:入力を受け取りModelとTemplateを制御
- Template:入出力を担当
本記事では、FlaskのViewとTemplateを理解するために「ルーティング」と「テンプレート」について解説します。
Flaskを利用するためのPython環境構築
PythonのWebフレームワークであるFlaskを利用するには、開発におけるPythonの環境構築が必要です。
Pythonの開発環境を構築するために、以下の手順を示します。
- Pythonのダウンロードとインストール
- VSCode(Visual Studio Code)のインストール
- Flaskのインストール
PythonとVSCodeインストールがまだできていない人は「【Python】ダウンロードとインストール方法から環境構築まで解説!」を一読ください。
また、Flaskのインストールや開発環境構築がまだできていない人は、「【Python】フレームワークFlaskとは?インストール方法から開発環境構築まで解説!」を一読ください。
Flaskによるルーティングとは
Flaskにてルーティングを利用する場合、以下の基本的な使い方を理解しましょう。
- ルーティングを設定する
- flask routesコマンドでルーティング情報を確認する
- FlaskのEndpoint(エンドポイント)を設定する
- Ruleに変数を設定する
それぞれの使い方を解説します。
Flaskによるルーティングを設定する
ルーティングとは、リクエスト先のURIと実際に処理する関数を紐づけることを指します。
Flaskでは、関数の先頭にデコレータと呼ばれる関数@app.route()
を追加することでルートを追加できます。
ここでは、例としてapp.pyに「Good morning!」を出力するルートを追加します。
# Flaskをインポート
from flask import Flask
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/")
def index():
return 'Hello World!'
@app.route("/morning")
def morning():
return 'Good morning!'
ターミナルにてflask run
コマンドを実行し、http://127.0.0.5000/morning
にアクセスするとGood morning!
が表示されます。
flask routesコマンドでルーティング情報を確認する
ターミナルにてflask routes
コマンドを実行し、ルーティング情報を確認してみましょう。
flask routes
Endpoint Methods Rule
-------- ------- -----------------------
index GET /
morning GET /morning
static GET /static/<path:filename>
上記のように、flask routes
コマンドによって「Rule」「Methods」「Endpoint」の3要素が確認できます。
各要素がどのような役割を持っているか後述で解説します。
HTMLフォームで利用するHTTPメソッド
HTTPメソッドは、クライアントがサーバーに対してリクエストを送信する際、サーバーに実行してほしい処理を伝えるために利用します。
HTTPメソッドにはいくつか種類がありますが、ここではGETメソッドとPOSTメソッドを記載します。
メソッド | 説明 |
---|---|
GET | 検索や情報取得の場合に利用される。 |
POST | ログインや問い合わせといったフォームの値を登録・更新などする場合に利用される。 |
FlaskのEndpoint(エンドポイント)を設定する
Endpointは通常APIにアクセスするためのURIを指しますが、FlaskではURIと紐づけられた関数名を指します。
エンドポイント名は、以下の記述で任意で名付けられます。
@app.route("/", endpoint="endpoint-name")
例えば、先ほど追加した@app.route("/morning")
にエンドポイント名を付与してみましょう。
@app.route("/morning", methods=["GET"], endpoint="morning-endpoint")
許可するHTTPメソッドを設定する
@app.route
といったデコレータ関数で許可するHTTPメソッドを指定できます。
@app.route("/morning", methods=["GET", "POST"])
上記のように、methodsにHTTPメソッド名を指定できます。
何も指定しない場合は、GETがデフォルトになります。
また、Flaskのバージョン2.0以降、route()
を省略できます。
@app.get("/morning")
@app.post("/morning")
どちらを利用してもHTTPメソッドを指定することができます。
Ruleに変数を設定する
デコレータである@app.route()
は、Ruleに変数を指定できます。
変数は、<変数名>
の形式で指定します。
以下のようにコードを追加してみましょう。
# Flaskをインポート
from flask import Flask
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/")
def index():
return 'Hello World!'
# /morning/<name>にすることで変数を指定
@app.route("/morning/<name>", methods=["GET", "POST"], endpoint="morning-endpoint")
# 関数の引数に変数であるnameを追加
def morning(name):
# Python3.6から導入されたf-stringで変数を埋め込む
return f'Good morning {name}!'
ターミナルにてflask routes
コマンドを実行すると、以下のように「Rule」「Methods」「Endpoint」が書き換わります。
Endpoint Methods Rule
---------------- --------- -----------------------
index GET /
morning-endpoint GET, POST /morning/<name>
static GET /static/<path:filename>
実際にターミナルにてflask run
コマンドを実行し、http://127.0.0.5000/morning/jobcode
と入力します。
オプションでコンバーターと呼ばれる型定義を利用して<コンバーター:変数名>
と記述し変数のデータ型も指定できます。
コンバーターの型 | 説明 |
---|---|
string | スラッシュなしのテキスト |
int | 正の整数 |
float | 正の浮動小数点 |
path | スラッシュ付きのテキスト許容 |
uuid | UUID文字列 |
Flaskによるテンプレートとは
Flaskにてテンプレートを利用する場合、以下の基本的な使い方を理解しましょう。
- テンプレートエンジンを利用する
- テンプレート(templates)を作成する
- Jinja2の基本的な使い方を理解する
それぞれの使い方を解説します。
Flaskによるテンプレートエンジンを利用する
テンプレートエンジンとは、テンプレート(templates)と呼ばれるひな形とデータを合成してHTMLファイルを出力するソフトウェアです。
Flaskのデフォルトテンプレートエンジンは、Jinja2が採用されています。
Flaskのインストールと同時に、Jinja2もインストールされています。
テンプレートエンジンを利用してHTMLをレンダリング(描画)するには、render_template
関数を利用します。
テンプレート(templates)を作成する
レンダリングするために必要なテンプレートを作成します。
VSCodeにて任意のディレクトリ内にtemplates
ディレクトリ(フォルダ)を作成し、templates
ディレクトリ内にindex.html
を作成します。
index.html
には以下を記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Flask-sample</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
次に、app.py
にてrender_template
をインポートし、コードを修正します。
# rende_templateをインポート
from flask import Flask, render_template
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/")
def index():
return render_template("index.html")
ターミナルにてflask run
コマンドを実行し、http://127.0.0.5000/
にアクセスしてみましょう。
render_template
関数によって、templates
ディレクトリ内のindex.html
指定し読み込まれます。
Jinja2の基本的な使い方|変数/if文/for文
一般的にJinja2では、以下の基本的な使い方があります。
- 変数の出力
- 条件式if文
- 繰り返しfor文
それぞれの基本的な使い方を解説する前に、上記の例で追加したmorning
関数で利用するmorning.html
を作成します。
上記で作成したtemplates
ディレクトリ内にmorning.html
を作成してみましょう。
変数の出力
変数の値を出力するには、.html
ファイルにて{{}}
を使います。
また、render_template
関数の第2引数以降で設定したキーワード引数あるいは辞書オブジェクトで指定した変数名が利用できます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Flask-sample</title>
</head>
<body>
<h1>Good morning {{ name }}!</h1>
</body>
</html>
from flask import Flask, render_template
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/")
def index():
return render_template("index.html")
# /morning/<name>にすることで変数を指定
@app.route("/morning/<name>", methods=["GET", "POST"], endpoint="morning-endpoint")
# 関数の引数に変数であるnameを追加
def morning(name):
# render_template関数の第二引数としてキーワード引数を指定
return render_template("morning.html", name=name)
ターミナルにてflask run
コマンドを実行し、http://127.0.0.5000/morning/name
のname
の部分を任意で入力しアクセスしてみましょう。
render_template
関数によって、templates
ディレクトリ内のmorning.html
が読み込まれ、指定した変数の値が出力されます。
条件式if文
次に、条件式if
文を利用するには、{% %}
を使います。
例えば、上記の変数出力のパターンで記述したmorning.html
をif
文で書き換えてみます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Flask-sample</title>
</head>
<body>
{% if name=="jobcode" %}
<h1>Good morning {{ name }}!</h1>
{% else %}
<h1>nameを変更してください。</h1>
{% endif %}
</body>
</html>
今回のケースは、変数nameが入力された際にアクセス可能な状態になるため、例として上記の条件分岐ができることを理解しておきましょう。
name=jobcodeを入力した場合
name=jobcode以外を入力した場合
繰り返しfor文
繰り返しfor
文を利用する時も、{% %}
を使います。
例えば、リストデータが存在した場合に以下の記述ができます。
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ui>
上記例のように、users
リストをfor
文で繰り返し、各リストデータからurl
やusername
を取り出し表示させています。
Flaskによるルーティングの具体的な使い方
ユーザーが最もルーティングを利用する具体例の一つは、ログインフォーム入力後の画面遷移になります。
ここでは、具体例としてログイン認証機能を持つアプリを想定し、ログインフォーム入力後の画面遷移を実施します。
以下は、サンプルアプリとして開発したログイン認証アプリと画像保存アプリを連携させたディレクトリ構成になります。
flask-project
├── .env
├── apps
│ ├── app.py
│ ├── config.py
│ ├── static/css
│ │ └── bootstrap.min.css
│ ├── auth
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ ├── static/css
│ │ │ └── style.css
│ │ ├── templates
│ │ │ └── auth
│ │ │ ├── base.html
│ │ │ ├── index.html
│ │ │ ├── login.html
│ │ │ └── signup.html
│ │ └── views.py
│ ├── image
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ ├── static/css
│ │ │ └── style.css
│ │ ├── templates
│ │ │ └── image
│ │ │ ├── base.html
│ │ │ ├── index.html
│ │ │ └── upload.html
│ │ └── views.py
| └── images
├── local.sqlite
└── migrations
Blueprintとは?
Blueprintとは、アプリケーションを分割するためのFlaskの拡張機能です。
Blueprintを利用すると、アプリケーション全体が大規模になっても簡潔な状態を保ち、アプリの保守性が向上します。
また、アプリを分割しているため1ファイルにおけるコードの可読性も高めます。
- アプリケーション全体の保守性向上
- 1ファイルにおけるコードの可読性向上
ディレクトリ構成が可視化しやすいため、開発効率も高まるメリットがあります。
Blueprintについて理解を深めたい人は「【Flask】Blueprintとは?使い方と実装方法を解説」を一読ください。
以下のコードは、ログイン認証機能を持つauthアプリのviews.pyになります。
また、ログインに関する関数のみ抜粋しています。
...省略...
# loginエンドポイントを作成する
@auth.route("/login", methods=["GET", "POST"])
def login():
loginform = LoginForm()
if loginform.validate_on_submit():
# メールアドレスからユーザー取得
user = User.query.filter_by(email=loginform.email.data).first()
# ユーザーが存在しパスワード一致ならログイン許可
if user is not None and user.verify_password(loginform.password.data):
login_user(user)
return redirect(url_for("image.index"))
# ログイン失敗メッセージを設定する
flash("メールアドレスかパスワードが不正です")
return render_template("auth/login.html", form=loginform)
...省略...
ルーティングの流れとしては、ユーザー情報がDBの値と一致すればログインを許可する仕様になっています。
また、ログインが許可された場合に別アプリへリダイレクトしています。
リダイレクト時にurl_forにて"アプリ名.関数名"
を設定することで指定した関数を処理できます。
ルーティングの動作確認
以下は、実際に作成したログイン画面になります。
ログインフォーム画面にて、必要なデータを入力しログインを試みます。
ログイン後、別アプリである画像一覧画面に遷移しました。
上記のように、分割したアプリ開発の中でルーティングは重要な概念です。
ログイン認証アプリに興味がある人は「【Flask】flask-loginによるログイン機能を実装した認証アプリ開発」を一読ください。
以下の内容を中心に解説しています。
- flask-loginの使い方を理解する
- サインアップ/ログイン認証/ログアウト機能の実装方法を理解する
- バリデーションチェックやデータベース操作を理解する
また、画像保存アプリに興味がある人は「【Flask】画像ファイルアップロード機能を実装した画像表示アプリ開発」を一読ください。
以下の内容を中心に解説しています。
- 画像ファイルアップロード機能の使い方を理解する
- 画像と紐づくデータベース操作を理解する
- 画像ファイルの表示方法と削除方法を理解する
コメント