クイックスタート

すぐ始めたいですか?このページはFlaskのイントロダクションに良いでしょう。Flaskはインストール済みと想定しています。もしまだならば、インストールセクションを確認してください。

最少のアプリケーション

最少のFlaskアプリケーションは以下のようなものになります:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

では、そのコードは何をしているのでしょうか?

  1. 最初に、Flaskクラスをimportしています。このクラスのインスタンスはWSGI(訳注: Pythonで標準化されている、WebアプリとWebサーバ間のインタフェース)アプリケーションになります。

  2. 次に、Flaskクラスのインスタンスを作成します。最初の引数はアプリケーションのモジュール(訳注: 簡単に言うと拡張子pyのPythonファイル)またはパッケージ(訳注: 簡単に言うとモジュールをまとめて格納したディレクトリ)の名前です。アプリケーションとして開始するかモジュールとしてimportするかによって名前が変化する('__main__'もしくは実際のimport名)ため、もし(この例のように)1つだけのモジュールを使っているときは、__name__を使うべきです。これはテンプレート、静的ファイルなどを探す場所をFlaskが知るために必要になります。さらなる情報については、Flaskのドキュメントを調べてください。

  3. それからroute()デコレータを使って、どのURLが関数をトリガーすべきかをFlaskに伝えます。

  4. 関数には名前が与えられ、その名前は対応するURLを生成するときにも使用されます(訳注: 関数名がurl_for()で対応するURLを作成するときに使うエンドポイント名になることを指していると思います)。そして関数は、ユーザのブラウザに表示したいメッセージを返します。

これをhello.pyのような名前で保存するだけです。Flask自身と衝突しないようにするため、自分のアプリケーションはflask.pyと名付けないように必ずしてください。

アプリケーションを実行するには、flaskコマンドでもpythonの-mスイッチにFlaskを指定しても、どちらも使用できます。実行できるようにする前に、FLASK_APP環境変数をexportして、実行するアプリケーションを端末(訳注: Windowsでのコマンドプロンプト、Linuxでの端末、SSHログインしているときのPuTTYやTera Termなど、コマンドラインで操作している環境を指します)へ伝える必要があります。

$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

Windows上では、環境変数の書き方はコマンドラインインタプリタに依存します。コマンドプロンプト上では:

C:\path\to\app>set FLASK_APP=hello.py

そしてPowerShell上では:

PS C:\path\to\app> $env:FLASK_APP = "hello.py"

違うやり方として、python -m flaskを使用できます:

$ export FLASK_APP=hello.py
$ python -m flask run
 * Running on http://127.0.0.1:5000/

これはとてもシンプルな内蔵サーバを起動し、それはテスト用には十分ですが、おそらく本番環境では使用したくはならないでしょう。デプロイ(訳注: 実行環境への移行のような意味合い)のオプションについては、展開の選択肢(Deployment Options)を参照してください。

それではhttp://127.0.0.1:5000/を見てください、あなたのhello worldを確認できるはずです。

外部から見えるサーバ

もしサーバを実行した場合、サーバは自分のコンピュータからだけアクセス可能で、他にはネットワークのどこからもアクセスできないことに気付くでしょう。デバッギングモードでは、アプリケーションのユーザがコンピュータ上で任意のPythonコードを実行可能になるために、これが標準設定になっています。

デバッギングを無効にしているか、ネットワーク上のユーザを信頼する場合、コマンドラインに--host=0.0.0.0を追加すれば、サーバへのアクセスを公開できます:

$ flask run --host=0.0.0.0

こうすると、全ての公開されているIP上でアクセスを受け付けるよう、OSへ伝えます。

サーバがスタートしない場合にするべきこと

もしpython -m flaskが失敗するときやflaskコマンドが存在しないときは、その原因であるかもしれない理由がいくつかあります。まず最初に、エラーメッセージを調べる必要があります。

古いバージョンのFlask

バージョン0.11以前のFlaskはアプリケーションを開始するときに別のやり方を使用していました。手短に言えば、flaskコマンドは存在せず、python -m flaskも使いませんでした。この場合には、2つの選択肢があります: Flaskを新しいバージョンへアップグレードするか、開発サーバドキュメントを調べて、サーバを実行する代わりのやり方を見つけてください。

間違った名前のimport

FLASK_APP環境変数はflask runでimportするモジュールの名前になります。モジュール名が正確でない場合には、スタートしようとしたとき(もしくは、もしデバッグを有効にしていた場合はアプリケーションへアクセスしようとしたとき)にimport errorが発生するでしょう。import errorは、何をimportしようとして、なぜ失敗したかを示しているでしょう。

最もありがちな(サーバ起動失敗の)理由は、typoか、appオブジェクトを実際に作成してはいないためです。

デバッグモード

(ただ、errorやstack traceをログに記録したいだけですか?その場合はApplication Errorsを確認してください)

flaskスクリプトはローカルの開発サーバをスタートするには便利ですが、コードを変更するたびに手動で再起動が必要になるでしょう。それはあまり便利ではなく、そしてFlaskはもっと便利に使えます。もしデバッグサポートを有効にすれば、コードを変更したときにサーバは自分自信で再読み込み(reload)するようになり、さらに、もし問題が起きた場合には役に立つデバッガも提供するようにもなります。

すべての(デバッグモードも含めた)開発機能を有効にするために、サーバの実行前に環境変数FLASK_ENVdevelopmentに設定してエクスポートできます:

$ export FLASK_ENV=development
$ flask run

(Windowsでは、exportの代わりにsetを使う必要があります)

これは以下のことを行います:

  1. デバッガを有効にします

  2. 自動再読み込みを有効にします

  3. Flaskアプリケーションのデバッグモードを有効にします。

環境(訳注: FLASK_ENVの設定とほぼ同じ意味合い)とは別に、FLASK_DEBUG=1をexportしてもデバッグモードを制御できます。

開発サーバのドキュメントでより多くのパラメータを説明しています。

注意

たとえforkした環境(訳注: Working with Debuggers参照、外部デバッガを使用したい場合にFlaskではforkした環境というものを設定可能)ではインタラクティブなデバッガが動かない(それによって本番環境のサーバでは内蔵デバッガが殆ど使用不可能になります)としても、それでも(デバッグモードや外部デバッガの使用は)任意のコードを実行できるようにします。これは深刻なセキュリティ上のリスクであり、従って本番環境のマシンでは決して使用してはいけません

実行中のデバッガのスクリーンショット:

screenshot of debugger in action

デバッガ使用に関するさらなる情報はWerkzeugドキュメントで見つけることができます。

他のデバッガを考えていますか?Working with Debuggersを確認してください。

経路設定(Routing)

最近のwebアプリケーションは、ユーザに役立つような意味のあるURLを使用します。もし、ページへ直接訪れるために記憶し直接指定できる意味のあるURLを使用していれば、ユーザはそのページをより好きになり、再訪問するようになるでしょう。

関数とURLを結び付け(bind)したいときは、route()デコレータを使用します。

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

@app.route('/hello')
def hello():
    return 'Hello, World'

もっとできることがあります!URLの一部を動的に変化させたり、複数のルールを関数に付与することも可能です。

変数のルール

<variable_name>のように一部へ目印をつけることで、URLに変数のセクションを追加することができます。こうすると、関数は<variable_name>をキーワード引数のように受け取るようになります。必須ではないですが、引数のタイプを指定するために、<converter:variable_name>のようにすればコンバータを使用できます。

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % escape(username)

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % escape(subpath)

コンバータの種類:

string

(標準設定)スラッシュ(/)以外の全てのテキストを受け付けます

int

正の整数を受け付けます

float

正の浮動小数点の値を受け付けます

path

stringに似ていますが、スラッシュ(/)を受け付けます

uuid

UUID文字列を受け付けます

URLと転送(Redirection)のユニークな振舞

最後のスラッシュ(/)の使い方が、以下の2つのルールでは異なっています。:

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

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

projectsエンドポイントの正規化(訳注: 記法の揺らぎを統一するような意味合い)されたURLでは、最後にスラッシュがあります。これはファイルシステムでのフォルダに似ています。もし最後のスラッシュなしでURLへアクセスした場合、Flaskは最後にスラッシュのある正規化されたURLへ転送(redirect)します。

aboutエンドポイントの正規化されたURLでは、最後にスラッシュがありません。これはファイルシステムでのファイルのパス名に似ています。もし最後にスラッシュを付けたURLへアクセスしたときは404の「Not Found」エラーが発生します。こうすると、これらのリソースに対するURLを唯ひとつに保てるため、検索エンジンが同じページを重複して登録することを防ぐ手助けになります。

URLの構築

ある特定の関数に対応するURLを構築するには、url_for()関数を使用します。それは関数名を最初の引数に受け付けて、さらに、URLルールの変数部分に対応する、好きな数だけのキーワード引数を受け付けます。不明な変数パートはqueryパラメータとしてURLの後ろ(訳注: ?key=valueの部分)に付けられます。

URLをテンプレートへハードコーディングする代わりに、(関数名から)URLへと逆変換するurl_for()関数を使ってURLを構築する方が、なぜ好ましいのでしょうか?(訳注: テンプレートの中でリンクなどがあったとき、そこへURLを直接記述するのではなく、リンク先で使いたい関数名からURLへ変換する処理を記述した方がなぜ好ましいか、という意味合い)

  1. URLをハードコーディングするよりもURLへ逆変換する方が、分かり易いことが多いためです。

  2. (URLを変更するとき)ハードコーディングされた(複数の場所に埋め込まれているかもしれない)URLを忘れずに手作業で変更する必要がある代わりに、(関数とURLを対応付けている箇所で)一気に変更することができます。

  3. URLを構築する処理では、特殊文字とユニコードのデータのエスケープ処理を透過的に扱います。

  4. 生成されたパスは常に絶対パスであり、相対パスによるブラウザ上での予想外の振舞を回避します。

  5. もしアプリケーションがURLのroot以外、例えば、/の代わりに/myapplicationへ置かれたときでも、url_for()は適切に処理します。

以下の例ではurl_for()を試すためにtest_request_context()メソッドを使っています。test_request_context()はFlaskに、Pythonシェルを使っている場合であってもリクエスト(訳注: HTTPなどの通信リクエスト)をを処理しているかのように振る舞うよう伝えます。コンテキストの局所的オブジェクト(Context Locals)を参照ください。

from flask import Flask, escape, 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(escape(username))

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))
/
/login
/login?next=/
/user/John%20Doe

HTTPメソッド

webアプリはURLへアクセスするときに異なるHTTPメソッドを使用します。Flaskで作業するときは、HTTPメソッドに親しんでおいた方が良いでしょう。標準設定の経路(route)は、GETメソッドにだけ応答します。異なるHTTPメソッドを処理するために、route()デコレータのmethod引数を使用できます。

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()

もしGETが(method引数の中に)存在する場合、Flaskは自動的にHEADメソッドのサポートを追加して、HTTP RFCに従って ``HEAD``リクエストを処理します。同様に、あなたにとって良いように、OPTIONSも自動的に実装されます。

静的ファイル

動的なwebアプリケーションでも静的ファイルを必要とします。普通は、静的ファイルはCSSとJavaScriptがもたらされるところです。webサーバがそれらを扱うように構成されていると理想的ですが、開発中はFlaskで同様な対応が可能です。パッケージの中またはモジュールの隣にstaticというフォルダを作成するだけで、アプリケーションから/staticで利用できるようになります。

静的ファイルに対応するURLを生成するには、特別な'static'というエンドポイント名を使用します:

url_for('static', filename='style.css')

この例のファイルは、ファイルシステム上のstatic/style.cssに保管されている必要があります。

テンプレートの変換(Rendering)

Pythonの中でHTMLを生成するのは楽しい作業ではなく、アプリケーションをセキュアに保つためにHTMLエスケープ処理を自分で行う必要があるために、実際にとても煩わしいものです。そのような理由から、FlaskはJinja2テンプレートエンジンを自動的に組み込んでいます。

テンプレートを変換するにはrender_template()メソッドを使用できます。あなたがしなければならないことは、テンプレート名と、キーワード引数としてテンプレートエンジンに渡したい変数の提供だけです。テンプレートをどのように変換するかの単純な例は以下のとおりです:

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)

Flaskはテンプレートをtemplatesフォルダの中から探します。もしアプリケーションがモジュールなら、そのフォルダはモジュールの隣にあり、もしパッケージなら、そのフォルダは実際にはパッケージの中にあります:

ケース 1: モジュール:

/application.py
/templates
    /hello.html

ケース 2: パッケージ:

/application
    /__init__.py
    /templates
        /hello.html

テンプレートではJinja2テンプレートの力を全て使うことができます。より詳細な情報はJinja2テンプレートドキュメントを確認してください。

これはテンプレートの例です:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

テンプレートの中では、get_flashed_messages()関数と同様に、request, session, g 1オブジェクトにもアクセスできます。

継承を使うとテンプレートは非常に便利です。テンプレートがどのように働くか知りたいときはTemplate Inheritanceパターンのドキュメントを確認してください。基本的にテンプレートの継承は(ヘッダ、ナビゲーション、フッタのように)ある要素を各ページで保持できるようにします。

自動エスケープが有効なので、もしnameがHTMLを含んでいた場合は、自動的にエスケープされます。もし変数を信頼できて、それが安全なHTMLであると分かっている(例えばwikiのマークアップをHTMLへ変換するモジュールから来ているなど)場合は、Markupクラスを使うか、|safeフィルタ(訳注: ここのフィルタはjinja2テンプレートエンジンの機能のひとつ)をテンプレートの中で使って、安全だと印を付けることができます。さらなる例はJinja2ドキュメントを確認してください。

Markupクラスがどう働くかの基礎的なイントロダクションは以下のとおりです:

>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'
Changelog

バージョン 0.5 で変更: 自動エスケープは全てのテンプレートで有効というわけではなくなっています。テンプレートが以下の拡張子であるときは、自動エスケープをトリガーします:.html, .htm, .xml, .xhtml。文字列から読み込まれたテンプレートでは、自動エスケープは無効になります。

1

gオブジェクトが何なのか不確かですか?それは、独自のニーズのために必要に応じて情報を格納できるものであり、より詳細な情報はそのオブジェクト(g)とUsing SQLite 3 with Flaskのドキュメントをチェックしてください。

リクエストデータへのアクセス

webアプリでは、クライアントがサーバへ送信したデータへ反応することが非常に重要です。Flaskでは、その情報(クライアントがサーバへ送信したデータ)はグローバルなrequestオブジェクトで提供されます。もしPython経験が多少あるならば、そのオブジェクトがグローバルでありながらスレッドセーフでもあるように、Flaskがどうやって管理しているのか、不思議に思うかもしれません。その答えはコンテキストの局所的オブジェクト(context locals)です:

コンテキストの局所的オブジェクト(Context Locals)

内部情報

もしcontext localsがどのように作用し、context localsを使ってどうやってテストできるかを理解したい場合は、このセクションを読み、そうでない場合は飛ばしてください。

いくつかのFlaskのオブジェクトはグローバルなオブジェクトですが、普通の種類のものではありません。それらのオブジェクトは実際には、ある特定のコンテキストに対して局所的なオブジェクトへのプロキシになります。長ったらしい説明ですが、実際には、理解するのは非常に簡単です。

コンテキストを処理中のスレッドだと想像してください。リクエストがやって来て、webサーバが新規スレッド(もしくは別のなにか、スレッド以外で並列処理を扱える土台となるオブジェクト)を作成する決定をします。Flaskが内部のリクエスト処理を開始するとき、Flaskはそのときのスレッドが活動中(active)のコンテキストであることを理解し、そのときのアプリケーションおよびWSGI環境とそのコンテキスト(スレッド)との結び付け(bind)をします。Flaskは、あるアプリケーションを起動しながら別のアプリケーションは壊さないような、賢いやり方でそれを実施します。

それでは、これはあなたにとって何を意味するのでしょうか?ユニットテストのようなことを行おうとしていない限り、基本的には完全に無視して構いません。(ユニットテストのようなことを行っているときは)リクエストオブジェクトが存在しないために、リクエストオブジェクトに依存しているコードが突然止まることに気付くでしょう。解決方法は、自分でリクエストオブジェクトを作成してコンテキストに結び付けることです。ユニットテストのための最も簡単な解決方法はコンテキストマネージャ(訳注: Pythonの仕様にある、with文と組み合わせて特別な処理をする仕組みで、ここの「コンテキスト」はHTTPリクエストとは関係ないか、またはHTTPリクエストのコンテキストとPython仕様にあるコンテキストの両者をかけた意味合い)のtest_request_context()を使用することです。with文と組み合わせると、テスト用のリクエストとやり取りできるように、テスト用リクエストとコンテキストとを結び付けます。以下はその例です:

from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'

別の可能なやり方は、WSGI環境全体をrequest_context()メソッドへ渡すことです。

from flask import request

with app.request_context(environ):
    assert request.method == 'POST'

リクエストオブジェクト

リクエストオブジェクトはAPIセクションにドキュメントがあり、ここでは詳細は網羅しません(詳細はRequestを確認してください)。ここでは、最もよくある操作のいくつかについて概観します。まず最初に、flaskモジュールをimportする必要があります:

from flask import request

その時点のリクエストのメソッドはmethod属性を使えば利用可能です。formのデータ(POSTまたはPUTリクエストで送信されるデータ)へアクセスするには、form属性を使用できます。以下は言及した2つの属性についての不足のない(どちらの用法も示した)例です:

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)

form属性にキーが存在しない場合はどうなるでしょうか?そのような場合は特別なKeyErrorを発生させます。それを標準のKeyErrorのようにcatchすることもできますし、そうしない場合には、代わりにHTTP 400Bad Requestのエラーページが表示されます。従って多くの場面では、その問題を特に処理する必要はないでしょう。

URLの中(?key=valueの部分)で与えられるパラメータへのアクセスにはargs属性を使用できます:

searchword = request.args.get('key', '')

ユーザはURLを変更することがあり、そのたびに400 bad requestのページを表示することはユーザにとって親切ではないので、URLパラメータはgetでアクセスするか、KeyErrorをcatchすることを推奨します。

リクエストオブジェクトの全てのメソッドと属性のリストは、Requestドキュメントを確認してください。

ファイルのアップロード

Flaskではアップロードされたファイルを容易に処理できます。自分のHTMLのformで、enctype="multipart/form-data"属性の設定だけは忘れず確実にしてください。そうしないと、そもそもブラウザがファイルを送信しないでしょう。

アップロードされたファイルはメモリ中かファイルシステムの一時的な場所に格納されます。それらのファイルはリクエストオブジェクトのfiles属性を調べることでアクセスできます。アップロードされた各ファイルは、そのdictionaryに格納されます。それはPython標準のfileオブジェクトのように振る舞いますが、サーバのファイルシステムへそのファイルを格納できるようにするsave()メソッドも持っています。以下は、それがどのように働くかを示す簡単な例です:

from flask import request

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/uploaded_file.txt')
    ...

アップロードされる前にクライアント側でどのようなファイル名であったかを知りたい場合は、filename属性にアクセスできます。しかし、その値は偽装される可能性があり決して信頼はできないことは覚えておいてください。クライアント側のファイル名を使用してサーバ側でファイルを格納したい場合は、Werkzeugが提供するsecure_filename()関数を通過させてください:

from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))
    ...

もっと良い例については、Uploading Filesパターンを調べてください。

クッキー(Cookies)

クッキーへアクセスするにはcookies属性が使用できます。クッキーを設定するには、レスポンスオブジェクトのset_cookieメソッドを使用できます。リクエストオブジェクトのcookies属性はクライアントが送信する全てのクッキーのdictionaryです。セッションを使用したい場合は、クッキーを直接使うのではなく、クッキーの上にいくらかセキュリティーを追加した、Flaskのセッションを代わりに使用してください。

クッキーの読取:

from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.

クッキーの格納:

from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

クッキーはレスポンスオブジェクトに設定されていることに注目してください。通常はview関数からはただ文字列を返すだけなので、あなたにとって良いように、Flaskはそれら(訳注: view関数の戻り値、クッキーなど)をレスポンスオブジェクトへと変換します。もしそれを自分で明示的に実行したい場合は、make_response()関数を使用して、それ(レスポンスオブジェクト)を変更できます。

ときには、レスポンスオブジェクトがまだ存在しない時点でクッキーを設定したいこともあるでしょう。これはDeferred Request Callbacksパターンを活用すれば可能です。

これについてはレスポンスについても確認してください。

転送(Redirects)とエラー

ユーザを別のエンドポイントへリダイレクトするには、redirect()関数を使用します; リクエストを早い段階でエラーコードと一緒に異常終了させるには、abort()関数を使用します:

from flask import abort, redirect, url_for

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

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()

これは、ユーザをindexページからアクセスできないページ(401はアクセス拒否を意味します)へとリダイレクトするため、いくぶんポイントを捉えていない例ですが、上記の関数がどのように機能するかを示しています。

標準設定では各エラーコードに対して白黒のエラーページを表示します。もしエラーページをカスタマイズしたい場合、errorhandler()デコレータを使用できます:

from flask import render_template

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

render_template()呼び出し後の``404``に注目してください。これは、そのページのステータスコードはnot foundを意味する404にするべきであることを、Flaskに伝えます。標準設定では200が想定されており、それは次のように翻訳されます: すべてうまく行きました。

より詳細はError handlersを確認してください。

レスポンスについて

view関数からの戻り値は自動的にレスポンスオブジェクトに変換されます。もし戻り値がstringの場合、stringをレスポンスのbodyに、ステータスコードを200 OKに、そしてmimeタイプをtext/htmlにしたレスポンスオブジェクトへ変換されます。もし戻り値がdictの場合、レスポンスを作成するためにjsonify()が呼び出されます。Flaskが(view関数の)戻り値をレスポンスへ変換するロジックは以下のとおりです:

  1. もし適切なタイプのレスポンスオブジェクトが返された場合は、それがviewから直接返されます。

  2. もしstringであれば、レスポンスオブジェクトはそのデータと標準設定のパラメータとを使用して作成されます。

  3. もしdictであれば、レスポンスオブジェクトはjsonify()を使用して作成されます。

  4. もしtupleが返された場合は、tuple内のアイテムは追加情報を提供できます。そのようなtupleは(response, status), (response, headers), または(response, status, headers)という形式でなければいけません。statusの値はステータスコードを上書きし、そしてheadersは追加ヘッダの値であるlistかdictionaryが可能です。

  5. もし上記のいずれも機能しない場合、戻り値は妥当なWSGIアプリケーションであるとFlaskは仮定し、それをレスポンスオブジェクトへ変換します。

もし結果となるレスポンスオブジェクトをviewの内側で捉えたい場合は、make_response()関数を使用できます。

以下のようなviewがあると想像してください:

@app.errorhandler(404)
def not_found(error):
    return render_template('error.html'), 404

必要なことは、make_response()でreturnの式を囲み、変更するためにレスポンスオブジェクトを取得し、それからそのレスポンスオブジェクトを返すだけです。

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp

JSONを使ったAPIs

APIを書いているときによくあるレスポンスのフォーマットにJSONがあります。FlaskでそのようなAPIの作成を始めることは簡単です。もしdictをviewから返した場合、それはJSONのレスポンスへ変換されます。

@app.route("/me")
def me_api():
    user = get_current_user()
    return {
        "username": user.username,
        "theme": user.theme,
        "image": url_for("user_image", filename=user.image),
    }

APIの設計によっては、JSONのレスポンスをdict以外のタイプでも作成したくなるかもしれません。そのような場合は、サポートされているJSONのデータタイプのシリアライズ(訳注: この場合ネットワークで通信可能な形式にするような意味合い)をするjsonify()関数を使用します。もしくは、より複雑なアプリケーションをサポートする、コミュニティのFlask拡張を調べてください。

@app.route("/users")
def users_api():
    users = get_all_users()
    return jsonify([user.to_json() for user in users])

セッション

リクエストオブジェクトに加えて、あるユーザに特有の情報をひとつのリクエストから次のリクエストへと格納できるようにする、sessionと呼ばれる2番目のオブジェクトもあります。これはクッキー上に実装されていて、クッキーに暗号学的な署名をします。これが意味することは、ユーザは自分のクッキーの内容を見ることはできますが、署名に使われた秘密鍵を知らないかぎり、変更はできないということです。

セッションを使用するためには、秘密鍵を設定しなければなりません。セッションがどのように働くかは、以下のとおりです:

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)

# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'

@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))

ここで言及されているescape()は、(この例のように)テンプレートエンジンを使用していない場合にエスケープ処理をします。

良い秘密鍵の生成のしかた

秘密鍵はできるだけでたらめなものにするべきです。暗号学的にでたらめであるデータの生成装置に基づいた、非常にでたらめなデータを生成する方法がオペレーティングシステムにはあります。手早くFlask.secret_key(もしくはSECRET_KEY)の値を生成するには、以下のコマンドを使用してください:

$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'

クッキーに基づいたセッションについての注意: Flaskはsessionオブジェクトに置かれた値を取り上げ、クッキーへシリアライズします。もしも複数のリクエストを跨いだ持続をしていない値が(sessionで)見つかり、実際にクッキーは有効であり、そして明確なエラーメッセージを得られないときは、ページのレスポンスにあるクッキーのサイズをチェックし、webブラウザによってサポートされているサイズと比較してください。

クライアント側に基づいた標準的なセッションに加えて、もしサーバ側で代わりにセッションを処理したい場合、これをサポートするFlask拡張がいくつかあります。

メッセージのフラッシュ表示

良いアプリケーションおよびユーザインタフェースとは、すべてフィードバック次第です。もしユーザが十分なフィードバックを得られない場合、おそらくアプリケーションを嫌いになって終わりです。Flaskはフラッシュ表示の仕組み(flashing system)によって、ユーザへフィードバックを与える非常にシンプルな方法を提供します。フラッシュ表示の仕組みは、リクエストの最後にメッセージを記録し、次の(ただ次だけの)リクエストでアクセスできるようにします。これは、普通はメッセージを表示するレイアウトのテンプレートと組み合わされます。

メッセージをフラッシュ表示させるにはflash()メソッドを使用し、メッセージを捉えるには、テンプレートでも利用可能なget_flashed_messages()が使用できます。不足のない(どちらの用法も示した)例についてはMessage Flashingを調べてください。

ログ機能(Logging)

Changelog

バージョン 0.3 で追加.

ときには、修正すべきであるにもかかわらず修正されていないデータを処理する状況におかれるかもしれません。例えば、明らかに適切でない形式のHTTPリクエストをサーバへ送信するクライアント側のコードがあるかもしれません。これは、ユーザのデータ改ざんや、クライアントのコードの失敗によって引き起こされるかもしれません。その状況では殆どの場合は400 Bad Requestを返せば大丈夫ですが、ときにはそれでは通用せず、コードを動かし続けなければならないことがあります。

起きてしまったそのようなうさんくさい何かをログしたいことがあるかもしれません(You may still want to log that something fishy happened)。これはloggerを重宝する状況です。Flask 0.3以降は、loggerが使用できるように事前設定されています。

以下はログを呼び出すいくつかの例です:

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')

付与されているloggerはPython標準のロギングのLoggerなので、さらなる情報は公式のloggingドキュメントを確認してください。

さらに、Application Errorsも読んでください。

WSGIミドルウェア内でのフック

アプリケーションにWSGIのミドルウェアを追加したい場合は、内部のWSGIアプリケーションをラップできます。例えば、lighttpdのバグへ対処するためにWerkzeugパッケージにあるミドルウェアのひとつを使いたい場合、以下のように実施できます:

from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)

Flask拡張の使用

(Flask)拡張は、よくあるタスクを達成する手助けをするパッケージです。例えば、Flask-SQLAlchemyはSQLAlchemyのサポートを提供し、シンプルかつ容易にSQLAlchemyをFlaskと一緒に使用できるようにします。

Flask拡張についてさらには、Extensionsを調べてください。

webサーバへのデプロイ

新しいFlaskアプリをデプロイする準備ができましたか?展開の選択肢(Deployment Options)へ進んでください。