より大きなアプリケーション

より大きなアプリケーションを作る場合に、モジュールではなくパッケージを用いるのは良い方法です。 これは非常に単純です。次のような小さいアプリケーションを考えてみましょう。:

/yourapplication
    /yourapplication.py
    /static
        /style.css
    /templates
        layout.html
        index.html
        login.html
        ...

単純なパッケージ

上の例を大きなアプリケーションにする場合、新しいフォルダ yourapplication を既存のフォルダの下に作成し、それ以下にあったすべてのファイルを yourapplication フォルダに移動します。 その後、 yourapplication.py__init__.py にファイル名を変更します。 (これらの作業を行う前に .pyc ファイルをまず削除してください。そうしないとうまく動作しません。)

以上を終えると次のように鳴るはずです。:

/yourapplication
    /yourapplication
        /__init__.py
        /static
            /style.css
        /templates
            layout.html
            index.html
            login.html
            ...

しかしどのようにアプリケーションを起動したらいいんでしょうか。ネイティブで使う python yourapplication/__init__.py は動作しません。 Pythonではパケージ内のモジュールがスタートアップファイルになることを嫌います。 しかし、これは大した問題じゃありません。 runserver.py という新しいファイルを作成して、 yourapplication フォルダに追加して次のような行を追加します。:

from yourapplication import app
app.run(debug=True)

これから何がわかるでしょうか。これでアプリケーションを少しばかり複数のモジュールに分割する方法がわかりました。 覚えていかなければいけないのは、次の事柄です:

  1. Flask アプリケーションオブジェクトは __init__.py の中で生成されなければいけません。 こうすればモジュールは各々安全にインポートされ、 __name__ 変数は適切なパッケージに解釈されます。
  2. すべてのビュー関数( route() デコレータで修飾された関数)は __init__.py の中でインポートされなければいけません。 正確にはオブジェクトそのものではなく、その関数を含むモジュールが __init__.py になければいけません。 インポートはファイルの 最後 で行ないましょう。

__init__.py の一例です:

from flask import Flask
app = Flask(__name__)

import yourapplication.views

そして views.py はこのようになります。:

from yourapplication import app

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

最終的にはこのような形になるはずです。:

/yourapplication
    /yourapplication
        /__init__.py
        /views.py
        /static
            /style.css
        /templates
            layout.html
            index.html
            login.html
            ...

admonition:: 循環インポート

しかしそれでもなお循環インポートを用いたアプローチではいくつか問題がありますが、もしデコレータを使うならこれ以外に方法がないのです。 この問題をどのように扱っているかについての考察は Becoming Big のセクションに書いてありますので確認してください。

モジュールを使う

ビューが10個以上あるような大きなアプリケーションはビューをモジュールに分割したほうがいいかもしれません。 まずそのようなアプリケーションの典型例を見てみましょう:

/yourapplication
    /yourapplication
        /__init__.py
        /views
            __init__.py
            admin.py
            frontend.py
        /static
            /style.css
        /templates
            layout.html
            index.html
            login.html
            ...

ビューは yourapplication.views パッケージに格納されています。 必ず空の __init__.py を置いてください。 ではまずviewパッケージの admin.py から始めましょう。

まず始めに Module オブジェクトをパッケージ名とともに作成しなければいけません。 これはすでに作成済みの Flask オブジェクトと同じような動きをします。 Flask のすべてのメソッドが使えるわけではないですが、大体は同じです。

手短に言えば、こんな感じです:

from flask import Module

admin = Module(__name__)

@admin.route('/')
def index():
    pass

@admin.route('/login')
def login():
    pass

@admin.route('/logout')
def logout():
    pass

同様のことを frontend.py でも行ないます。そしてモジュールをアプリケーション(__init__.py)に登録することを忘れないようにします。こんな感じです。:

from flask import Flask
from yourapplication.views.admin import admin
from yourapplication.views.frontend import frontend

app = Flask(__name__)
app.register_module(admin)
app.register_module(frontend)

モジュールを扱った時と何が違うのでしょうか?主にURL生成に影響があります。 url_for() 関数を覚えていますか?モジュールを扱っていないときは第1引数に関数名を受け付けていました。 この第1引数を”エンドポイント”と呼びます。あるモジュールを扱っているときは、いままで紹介したように同じモジュール内の関数名はドットを使わずに渡すことができます。 もしURLを他のモジュールに渡したいときは、渡したい先のモジュール名をプレフィックスとして、その後にドットをつけ関数名をつなげて渡します。

混乱させてしまったでしょうか。明確にするために同じ例を用いて確認しましょう。 あるモジュール内のメソッド(例えば admin )があって、異なるモジュール(例えば frontend )へリダイレクトしたいとしましょう。この場合は次のような形になります。:

@admin.route('/to_frontend')
def to_frontend():
    return redirect(url_for('frontend.index'))

@frontend.route('/')
def index():
    return "I'm the frontend index"

次に同じモジュール内の別の関数にリダイレクトしたい場合を考えてみましょう。 この場合は上の例で行ったようにフルパスを与えるかあるいは単に関数名を与えます。:

@frontend.route('/to_index')
def to_index():
    return redirect(url_for('index'))

@frontend.route('/')
def index():
    return "I'm the index"

モジュールとリソース

New in version 0.5.

モジュールが実際のPythonパッケージ内にある場合、それはある静的ファイルかテンプレートでしょう。 次のようなアプリケーションを考えます:

/yourapplication
    __init__.py
    /apps
        /frontend
            __init__.py
            views.py
            /static
                style.css
            /templates
                index.html
                about.html
                ...
        /admin
            __init__.py
            views.py
            /static
                style.css
            /templates
                list_items.html
                show_item.html
                ...

静的なフォルダは自動的にURLに反映されます。 たとえばもし admin モジュールが /admin というプレフィックスのURLで公開された場合、その中の静的フォルダ内のスタイルシートにアクセスしたい場合は /admin/static/style.css にアクセスすればよいということになります。 adminモジュール内の静的ファイルに対するURLエンドポイントは admin.static となります。これはアプリケーション内の通常の静的フォルダを static として参照するのと同様です。

テンプレートを参照したい場合は、単にモジュール名をプレフィックスにしてアクセスすればよいだけです。 ここまでの例で言えば、 render_template('admin/list_items.html') という具合です。 テンプレートをプレフィックスなしでアクセスすることはできません。これはURLルールのように自明ではありません。