Python 製のマイクロフレームワーク「Flask」で Web アプリを作ってみた
Python で Web アプリを作れる「Flask フラスク」というフレームワークを試してみる。
目次
- Flask のインストール
- 最も簡単な例を作る
- HTML ファイルを返してみる
- 静的ファイルを返す
- 「Blueprint」でルーティングを分割する
- Flask RESTful を使ってみる
- 今回はココまで
Flask のインストール
まずは pipenv でプロジェクト環境を作り、Flask をインストールする。
$ pipenv --python 3.7
$ pipenv install flask
最も簡単な例を作る
まずは最も簡単な例を作ってみよう。
main.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World'
if __name__ == '__main__':
app.run()
まず変数 app を定義する。ちょうど Node.js の Express みたいな感じだ。
ルーティングは @app.route() というデコレータで定義する。ココでは / へのアクセス時に実行する関数 (def index()) を指定している。index() 関数はココでは Hello World という文字列だけをレスポンスしている。
最後は Python おなじみのおまじないで、本ファイルが直接実行された時だけ app.run() を実行するようにしている。
ココまで出来たら、次のように実行する。
$ pipenv run python main.py
すると http://localhost:5000/ に Web サーバが起動するので、ブラウザでココにアクセスしてみる。すると Hello World と表示されるはずだ。
HTML ファイルを返してみる
続いて、HTML ファイルをレスポンスしてみる。
main.py
from flask import Flask, render_template
app = Flask(__name__)
# 他のルーティング定義はココに書いていく
@app.route('/', defaults = { 'path': '' })
@app.route('/<path:path>')
def index(path):
return render_template('index.html')
if __name__ == '__main__':
app.run()
必要なのは render_template() 関数部分。コレで ./templates/index.html を返すようになる。ということで、templates ディレクトリを作り、その下に適当な index.html を入れておこう。
内部的には「Jinja2」というテンプレートエンジンをかませているらしいので、Java の JSP とか Ruby の Rails とかみたいに、専用のテンプレート記法を使った HTML が書けるらしい。今回は割愛。
@app.route('/', defaults = { 'path': '' })
@app.route('/<path:path>')
この部分が分かりにくかったので整理しておく。
まず1行目で、「/ なしのアクセス」「/ のみのアクセス」を捉え、変数 path の値を空文字で初期化している。
- 参考 : python - Capture arbitrary path in Flask route - Stack Overflow
- 参考 : Flask - Catch-all route | flask Tutorial
- 参考 : Python – Flask Default Routeは可能ですか? - コードログ
2行目は /【パス指定】 というアクセスに対応するモノ。<path:path> の手前の path は、「Converter」という Flask の機能。後ろの path は、続けて書く def index(path): の仮引数 path にあたる。なので
@app.route('/', defaults = { 'path': '' })
@app.route('/<path:my_path>')
def index(my_path):
とすると、違いが分かりやすくなるだろう。
Flask は Express.js と同様、ルーティングを定義した順に走査していく。この記述が app.run() の直前にあれば、# 他のルーティング定義はココに書いていく と記載した部分のルーティングで該当しないパスを、この index() 関数が拾って処理することになる。コレを「Catch-All Route」と呼ぶ。
- 参考 : いまさらながら Flask についてまとめる 〜Routing〜 - 適当おじさんの適当ブログ
- 参考 : Quickstart — Flask Documentation (1.1.x)
- 参考 : Python - Flask Default Route possible? - Stack Overflow
- 参考 : Routing - Flask Pedia
index.html はどこに置いておくのか、というと、./templates/index.html というパスに置いておく必要がある。デフォルトでは ./templates/ ディレクトリ配下を探しに行く仕組みになっているからだ。それ以外のディレクトリを指定する場合は Flask() の定義時に次のように指定する。
app = Flask(__name__, template_folder = '../dist')
こうすれば、Flask の作業ディレクトリ (main.py の場所) より一階層上に上ったところの dist/ ディレクトリを探しに行ってくれるようになる。
静的ファイルを返す
静的ファイルについては、./static/ というディレクトリに置いておくと自動的にレスポンスしてくれる。起点となるディレクトリを変更したい場合は、次のように static_folder で指定すれば良い。
app = Flask(__name__, static_folder = '../dist/static', template_folder = '../dist')
「Blueprint」でルーティングを分割する
Express の Router() のように、Flask も「Blueprint」という仕組みでルーティングを別ファイルに切り出したりできる。
main.py
from flask import Flask, render_template
app = Flask(__name__, static_folder = '../dist/static', template_folder = '../dist')
# 追加
from my_api import my_blueprint
app.register_blueprint(my_blueprint)
@app.route('/', defaults = { 'path': '' })
@app.route('/<path:path>')
def index(path):
return render_template('index.html')
if __name__ == '__main__':
app.run()
app.register_blueprint() というのを追加した。import している my_api というファイルは以下。
my_api.py
from flask import Blueprint
# Blueprint を作成する
my_blueprint = Blueprint('my_api', __name__, url_prefix = '/my-api')
# ルーティング定義
@my_blueprint.route('/example')
def example():
return 'Hello From Example'
このようにすると、Blueprint によって http://localhost:5000/my-api/ という階層ができ、その中で定義したルーティングに従い、http://localhost:5000/my-api/example にアクセスすると Hello From Example というテキストが返ってくる。
- 参考 : Python + Flask + Blueprint で複数のアプリケーションを登録する際に気をつけること - Qiita
- 参考 : いまさらながら Flask についてまとめる 〜Blueprint〜 - 適当おじさんの適当ブログ
Flask RESTful を使ってみる
Flask で REST API を作りやすくしてくれる「Flask RESTful」というパッケージも使ってみる。
まずは次のようにインストール。
$ pipenv install flask_restful
main.py は先程と同じなので割愛。my-api.py を import する作りにしてある。
一方、my-api.py は次のように修正する。
my-api.py
from flask import Blueprint
from flask_restful import Api, Resource
# (さっきのまま) Blueprint を作成する
my_blueprint = Blueprint('my_api', __name__, url_prefix = '/my-api')
# 追加 : Flask RESTful のクラスを定義する
my_api = Api(my_blueprint)
# (さっきのまま) 普通のルーティングはそのままで良い
@my_blueprint.route('/example')
def example():
return 'Hello From Example'
# 追加 : RESTful なリソースごとに class を定義する
class User(Resource):
# ココでは固定値を返すが、「1件取得」の関数を定義する
def get(self):
return {
'name': 'Neo',
'age' : 99
}
# 追加 : 作成したリソースのルーティングを定義する
my_api.add_resource(User, '/users')
こんな感じ。
コレで http://localhost:5000/my-api/users にアクセスすると、{"name": "Neo", "age": 99} という JSON が取得できる。
REST API でよくある「ID を指定して1件のリソースを取得」とか、「POST メソッドでデータを受け取り処理する」とかいう実装もできる。
今回はココまで
Flask 本体は小さなフレームワークで、REST API 構築や DB との O/R マッピングなど、やりたいことに合わせて Flask ファミリーのパッケージを追加していく形になる。とてもシンプルに実装できて、小規模開発なら必要十分という感じ。