Blow Up by Black Swan

Python-Flask の使い方(クイックスタート編 Part.2)

クイックスタート編のPart.2です。今回はWebアプリケーションフレームワークのもっとも基本的な機能となるルーティング機能についてです。

・各記事の記載内容
Part.1 -> 1.最小アプリケーション~3.デバッグモード
Part.2 -> 4.ルーティング
Part.3 -> 5.スタティックフォルダ〜7.リクエストデータへのアクセス
Part.4 -> 8.リダイレクトエラー〜最後

公式ドキュメント: Quickstart – Flask Documentation

※なお当記事は 2019 年 9 月現在の最新バージョンである Flask1.1.x の公式ドキュメントに基づいています。今後の Flask や Python のアップデートによっては記事内容に何らかの齟齬が生じることもありますので、事前にバージョンを確認頂くか、適宜公式ドキュメントを参照頂ければと思います。

4. ルーティング

最近のモダンウェブアプリケーションでは、ユーザーが理解しやすいよう、有意味なURLが使われます。あるページが有意味なURLを持ち、直接そのページに訪れることができとしたら、ユーザーはそのページを好み、再訪する傾向にあります。

関数とURLを結びつけるにはroute()デコレータを使います。route()デコレータでURLを指定することで、そのURLにアクセスがあった場合、デコレートされた関数が実行され、データ処理や次の画面への遷移などが行われます。Flaskのルーティングでは、URLの一部を動的に生成したり、関数に複数のルールを付け加えたりすることもできます。

from flask import Flask
app = Flask(__name__)

# ホーム用のURL
@app.route('/')
def index():
    return 'Index Page'

# URLが"/hello"
@app.route('/hello')
def hello():
    return 'Hello, World'
quickstart2
quickstart3

4-1. URLの変数ルール

ルートデコレータで<変数名>を記載することでURLに変数セクションを加えることができます。これは、ルーティングした関数(ルートデコレータを持つ関数)は、URLクエリなどから<変数名>をキーワード引数として受け取ります。オプションとして、引数の型を指定するためにコンバーター(型を指定する機能)も利用することができ、<converter:variable_name>と記載します(コンバーターの型と引数が一致しない場合エラーになる)。

  • <username>…URLに変数を利用する時の記法
  • <int:post_id>…このようにすることで、型を指定できる(コンバーター:converter)
  • コンバーター一覧
    • string…デフォルト。文字列型を引き入れる
    • int…整数型
    • float…小数点型
    • path…stringに似ているが、/(スラッシュ)にも対応する
    • uuid…UUIDの文字列
  • ※ここで使われている「%」は文字列置換のもの
from flask import Flask
app = Flask(__name__)

@app.route('/')    #一つ目の指定URL
def index():
    return 'Index Page'

# "<username>"が画面に表示される
@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username

# "<post_id>"が表示される(但し、数値型でないと「404 not found」となる)
@app.route('/post/<int:post_id>')
def show_post(post_id):
    return 'Post %d' % post_id

# "/path/"の後の"<sub_path>"を表示する
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    return 'Subpath %s' % subpath
quickstart4
quickstart5
quickstart6

4-2. ユニークなURL/リダイレクトのふるまい

次の2つのコードは末尾のスラッシュがあるかという点で異なります。

projectsをエンドポイントとするURLは、末尾にスラッシュを持ちます。これはファイルシステムのフォルダ表記に似ていますが、ユーザーが末尾にスラッシュなしでアクセスした場合でも、Flaskは末尾にスラッシュをもつ正規のURLに自動でリダイレクトします。

一方、aboutエンドポイントのURLは、末尾にスラッシュを持ちません。これはファイルのパスネームに類似していますが、末尾にスラッシュをつけてアクセスすると”404 NOT FOUND”エラーが出ます。これはURLがユニーク(一意)のものであることを担保し、サーチエンジンが同じページを二度もインデックスしないようにする役割を持ちます。

  • エンドポイントが/の場合、flaskが読み替えてくれる
  • エンドポイントが/でない場合、/ありでアクセスすると「404 not found」になる
from flask import Flask
app = Flask(__name__)

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')        #'/about/'でアクセスするとエラーになる
def about():
    return 'The about page'
quickstart7
quickstart8

4-3. URLの生成

特定の関数に対応するURLを生成するにはurl_for()関数を使います。関数名を第1引数として受け入れ、キーワード引数とともにURLを生成します。キーワード引数はURLの変数ルールと同じです。不明な変数部分はクエリパラメータとしてURLに追加されます。

<テンプレート内でURLをハードコーティング(URLを細かく指定)する代わりにurl_for()関数を使う理由>

  1. URLを生成する方がハードコーティングするより、構造が理解しやすくなる
  2. ハードコーディングされたURLを毎回手動で全て変更する代わりにURLを一気に変更することができる
  3. ユニコードデータや特殊文字を透明性をもって処理する
  4. 生成されたpathは常に絶対pathのため、相対pathによってブラウザが予期せぬ挙動に走ることを防ぐことができる
  5. アプリケーションがルートURL外に規定されている場合(“/”ではなく”/myapplication”下に規定されるようなとき)も、url_for()関数は適切に処理してくれる
  • url_for( func_name, keyword_args )…特定の関数に対応するURLを生成するメソッド
    • 第1引数には関数名、それ以後にはキーワード引数を入れる
    • キーワード引数は、URL内の変数ルール((4-1)参照)に従い、該当しない場合はクエリパラメーターとしてURLに連結される
  • app.test_request_context()…pythonシェル内で、リクエストが実際にあったかのような状況を作ってテストをするためのメソッド
    • withブロックでリクエストポイント(あるURLにリクエストを送る状態)を作り出せる
    • Context Locals参照
from flask import Flask, url_for

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(username)

with app.test_request_context():
    print(url_for('index'))                         # => 出力URL: "/"
    print(url_for('login'))                         # => 出力URL: "/login"
    print(url_for('login', next='/'))               # => 出力URL: "/login?next=/" スラッシュが不明変数になるため、クエリパラメータとして処理されている 
    print(url_for('profile', username='John Doe'))  # => 出力URL: "/user/John%20Doe"  キーワード引数"<username>"が"app.route"のURLルール"<username>"として処理される

4-4. HTTPメソッド

ウェブアプリケーションは、URLにアクセスする際、様々なHTTPメソッドを使っています。Flaskを使う上では、HTTPメソッドについて熟知する必要があります。デフォルトでは、ルートデコレータはGETメソッドのみに反応します。他のHTTPメソッドを処理するには、ルートデコレータのキーワード引数methodsを使用します。

GETが指定された場合、Flaskは自動的にHTTP RFCに沿って、HEADメソッドをサポートし、処理します。また同様にOPTIONSも自動的に実装されます。

  • app.route( url, methods )…デフォルトではGETリクエストのみに対応する
    • HEADやOPTIONも自動で対応してくれる
from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return do_the_login()
    else:
        return show_the_login_form()

続きは次の記事へ。

Python-Flask の使い方(クイックスタート編 Part.3)