Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

Flaskを触ってみる 1

Flaskですがあんまり書かれてなさそうなので書いておきます。

Flaskはmitsuhiko先生が作ったmicroframeworkです。
Flaskが指すmicroは単純に小さいというわけではなく、他のライブラリをつなぎ、シンプルなAPI
提供する小さなフレームワークのようなイメージです。

Flaskは

  1. werkzeug
  2. jinja2

に依存し、単体の機能はそれらに任せています.
Flaskそれらをうまくつなぎ合わせ、シンプルなAPIをユーザに提供しています。

そのため、Flaskは1ファイルで構成されています。
(つなぎの部分なので小さい。APIのドキュメント込みで900行を切っている)

一応Flaskはmicroframeworkとしていますが、コアはwerkzeugです。
werkzeugは大規模サイトなどの実績もあり、大変便利なライブラリです。
Flask自体で提供されていない機能などがあったとしても、werkzeugベースである以上
容易に拡張実装することも可能です。
そのためmicroといっても大きなポテンシャルを秘めていると言えます。

インストール

easy_install Flask

でインストールできます。

Flaskは

  1. werkzeug
  2. jinja2

にのみ依存しています。
もちろんその他に必要なものがあれば各自で用意する必要があります。

はじめの一歩

まずは定番のHello Worldを出してみましょう。

from flask import Flask
app = Flask(__name__)

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

if __name__ == '__main__':
    app.run()

非常にシンプルですね。
このファイルをhello.pyとして保存し、実行します。

python hello.py

実行後、http://localhost:5000にアクセスすると"Hello World"と表示されます。

簡単に説明しておくとこんな感じです。

  1. FlaskクラスはWSGI Application
  2. WSGI Applicationをインスタンス
  3. デコレータでApplicationのrouting設定をしている
  4. app.run()でローカルサーバを立ち上げて実行している

見慣れてるひともいるかも知れないけどFlaskのインスタンスからデコレータを使用しています。
なので@app.routeと書いています。
イメージとしてはこんな感じになってます。

class Flask(object):

    def route(self, rule **options):
        def decorator(f):
            # add rule!!
            ....

            return f

        return decorator

とりあえず基本としては

  1. Flaskをインスタンス化しWSGI Applicationを作る
  2. routeでroutingを設定する
  3. 動かすときはrun

を覚えておくだけでいいでしょう。

デバッグモード

デバッグモードで動かすときは

app.debug = True
app.run()

あるいは

app.run(debug=True)

とします。
デバッグモードをTrueにしておくとエラー発生時にwerkzeugのエラー画面が出ます。
werkzeugのエラー画面は非常に便利なので開発時にはデバッグモードにすることをオススメします。

Routing

URLにビュー関数を結びつける処理になります。
Routingはrouteメソッドで設定します。
RoutingはwerkzeugのRoutingを使用しています。

例:

@app.route('/')
def index():
    # index page
    pass

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    pass

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

URLの一部の値を変数で受け取る場合には<>で囲み、Routingの設定に記述します
記述すると設定した変数名と同じ名前でビュー関数に渡されます。
便利ですね。
また変数名の前にconverterを記述することができます。

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

ではpost_idにはint型で値が渡されてきます。

Routingの逆引き

逆引きはtest_request_contextとurl_forを使用して行うことができます。

>>> from flask import Flask, url_for
>>> app = Flask(__name__)
>>> @app.route('/')
... def index(): pass
...
>>> @app.route('/login')
... def login(): pass
...
>>> @app.route('/user/')
... def profile(username): pass
...
>>> with app.test_request_context():
... print url_for('index')
... print url_for('login')
... print url_for('profile', username='John Doe')
...
/
/login
/user/John%20Doe

HTTP Method

Routingでは許可するHTTP Methodも指定できます。
デフォルトではGETのみの許可になります。

GETもPOSTも許可する場合は以下のように記述します。

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

HTTP Methodは以下が指定可能です。

  • GET
  • HEAD
  • POST
  • PUT
  • DELETE

静的ファイルの扱い

javascriptcssは開発時にも必要です。
静的ファイルはurl_forで指定します。

url_for('static', filename="app.js")

この場合URLは"/static/style.css"となります。
静的ファイルはFlaskを走らせているpythonファイルのあるDirを起点に配備されます。

以下のような構成の場合

-- jqueryexample.py
-- static
`-- app.js

`-- templates
|-- index.html
`-- layout.html

app.jsを静的ファイルとして配備するには

url_for('static', filename="app.js")

でURLを生成させます。

テンプレート

Flaskはテンプレートエンジンにjinja2を使用しています。
テンプレートの記述方法などは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)

render_template関数にはテンプレート名、変数を指定します。
テンプレートの置き場ですがFlaskを走らせているpythonファイルのあるDir配下の"templates"Dirに置きます。

-- example.py <-- Application Codeが書いてある

`-- templates
|-- hello.html
`-- layout.html

Requestの処理

今まではRequestの処理がほとんどないケースを見てきました。
なのでRequestオブジェクトについても触れておきます。

Requestオブジェクトは引き数で渡されてきません。
importするだけで使用できます。

from flask import request

@app.route('/login', method=['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'
    # this is executed if the request method was GET or the
    # credentials were invalid

まあこれが実現できているカラクリがあるのですが今回は参照方法のみにしておきます。
requestの実体はwerkzeugのRequestオブジェクトを継承したものです。詳細はwerkzeugのドキュメントみてください。
jsonのメソッドを生やしただけ)

とそこそこ長くなったので今回はここまで。