ブループリントを使用したモジュラーアプリケーション
バージョン0.7の新機能。
Flaskは、ブループリントの概念を使用して、アプリケーションコンポーネントを作成し、アプリケーション内またはアプリケーション間で共通のパターンをサポートします。 ブループリントは、大規模なアプリケーションの動作を大幅に簡素化し、Flask拡張機能がアプリケーションの操作を登録するための中心的な手段を提供します。 Blueprint
オブジェクトはFlask
アプリケーションオブジェクトと同様に機能しますが、実際にはアプリケーションではありません。 むしろ、それはアプリケーションを構築または拡張する方法の青写真です。
なぜ青写真?
Flaskの青写真は、次の場合を対象としています。
- アプリケーションを一連の青写真に分解します。 これは、大規模なアプリケーションに最適です。 プロジェクトは、アプリケーションオブジェクトをインスタンス化し、いくつかの拡張機能を初期化し、ブループリントのコレクションを登録することができます。
- URLプレフィックスやサブドメインでアプリケーションのブループリントを登録します。 URLプレフィックス/サブドメインのパラメーターは、ブループリント内のすべてのビュー関数で共通のビュー引数(デフォルト)になります。
- 異なるURLルールを持つアプリケーションにブループリントを複数回登録します。
- ブループリントを介して、テンプレートフィルター、静的ファイル、テンプレート、およびその他のユーティリティを提供します。 ブループリントは、アプリケーションを実装したり、機能を表示したりする必要はありません。
- Flask拡張機能を初期化するときに、これらのケースのいずれかのアプリケーションにブループリントを登録します。
Flaskのブループリントは、実際にはアプリケーションではないため、プラグイン可能なアプリではありません。これは、アプリケーションに複数回登録できる一連の操作です。 複数のアプリケーションオブジェクトがないのはなぜですか? これは可能ですが(アプリケーションディスパッチを参照)、アプリケーションには個別の構成があり、WSGIレイヤーで管理されます。
ブループリントは、代わりにフラスコレベルでの分離を提供し、アプリケーション構成を共有し、登録時に必要に応じてアプリケーションオブジェクトを変更できます。 欠点は、アプリケーションオブジェクト全体を破棄せずに、アプリケーションが作成された後はブループリントの登録を解除できないことです。
ブループリントの概念
ブループリントの基本的な概念は、アプリケーションに登録されたときに実行する操作を記録することです。 Flaskは、リクエストをディスパッチし、あるエンドポイントから別のエンドポイントにURLを生成するときに、ビュー関数をブループリントに関連付けます。
私の最初の青写真
これは非常に基本的な青写真がどのように見えるかです。 この場合、静的テンプレートの単純なレンダリングを行うブループリントを実装する必要があります。
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
simple_page = Blueprint('simple_page', __name__,
template_folder='templates')
@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
try:
return render_template('pages/%s.html' % page)
except TemplateNotFound:
abort(404)
@simple_page.route
デコレータを使用して関数をバインドすると、ブループリントは、後で登録するときに、アプリケーションに関数show
を登録する意図を記録します。 さらに、関数のエンドポイントの前に、Blueprint
コンストラクター(この場合はsimple_page
)に与えられたブループリントの名前を付けます。 ブループリントの名前はURLを変更せず、エンドポイントのみを変更します。
ブループリントの登録
では、その青写真をどのように登録しますか? このような:
from flask import Flask
from yourapplication.simple_page import simple_page
app = Flask(__name__)
app.register_blueprint(simple_page)
アプリケーションに登録されているルールを確認すると、次のことがわかります。
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
<Rule '/' (HEAD, OPTIONS, GET) -> simple_page.show>]
最初のものは明らかに静的ファイルのアプリケーション自体からのものです。 他の2つは、simple_page
ブループリントの show 機能用です。 ご覧のとおり、ブループリントの名前のプレフィックスとドット(.
)で区切られています。
ただし、ブループリントはさまざまな場所にマウントすることもできます。
app.register_blueprint(simple_page, url_prefix='/pages')
そして確かに、これらは生成されたルールです:
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/pages/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
<Rule '/pages/' (HEAD, OPTIONS, GET) -> simple_page.show>]
その上、ブループリントを複数回登録できますが、すべてのブループリントがそれに適切に応答するわけではありません。 実際、ブループリントを複数回マウントできるかどうかは、ブループリントの実装方法によって異なります。
ブループリントリソース
ブループリントはリソースも提供できます。 提供するリソースについてのみブループリントを導入したい場合があります。
ブループリントリソースフォルダ
通常のアプリケーションと同様に、ブループリントはフォルダーに含まれていると見なされます。 複数のブループリントを同じフォルダーから作成することもできますが、そうである必要はなく、通常はお勧めしません。
フォルダは、Blueprint
の2番目の引数(通常は __ name __ )から推測されます。 この引数は、どの論理Pythonモジュールまたはパッケージがブループリントに対応するかを指定します。 実際のPythonパッケージを指している場合、そのパッケージ(ファイルシステム上のフォルダー)はリソースフォルダーです。 モジュールの場合、モジュールが含まれているパッケージはリソースフォルダーになります。 Blueprint.root_path
プロパティにアクセスして、リソースフォルダが何であるかを確認できます。
>>> simple_page.root_path
'/Users/username/TestProject/yourapplication'
このフォルダからソースをすばやく開くには、open_resource()
機能を使用できます。
with simple_page.open_resource('static/style.css') as f:
code = f.read()
静的ファイル
ブループリントは、static_folder
引数を使用してファイルシステム上のフォルダーへのパスを指定することにより、静的ファイルを含むフォルダーを公開できます。 これは、絶対パスまたはブループリントの場所からの相対パスのいずれかです。
admin = Blueprint('admin', __name__, static_folder='static')
デフォルトでは、パスの右端の部分はWeb上で公開されている場所です。 これは、static_url_path
引数で変更できます。 ここではフォルダの名前がstatic
であるため、ブループリントのurl_prefix
+ /static
で使用できます。 ブループリントのプレフィックスが/admin
の場合、静的URLは/admin/static
になります。
エンドポイントの名前はblueprint_name.static
です。 アプリケーションの静的フォルダーの場合と同じように、url_for()
を使用してURLを生成できます。
url_for('admin.static', filename='style.css')
ただし、ブループリントにurl_prefix
がない場合、ブループリントの静的フォルダーにアクセスすることはできません。 これは、この場合、URLが/static
になり、アプリケーションの/static
ルートが優先されるためです。 テンプレートフォルダーとは異なり、ファイルがアプリケーション静的フォルダーに存在しない場合、ブループリント静的フォルダーは検索されません。
テンプレート
ブループリントにテンプレートを公開させたい場合は、 template_folder パラメーターをBlueprint
コンストラクターに提供することでそれを行うことができます。
admin = Blueprint('admin', __name__, template_folder='templates')
静的ファイルの場合、パスは絶対パスにすることも、ブループリントリソースフォルダーからの相対パスにすることもできます。
テンプレートフォルダはテンプレートの検索パスに追加されますが、実際のアプリケーションのテンプレートフォルダよりも優先度は低くなります。 そうすれば、ブループリントが実際のアプリケーションで提供するテンプレートを簡単にオーバーライドできます。 これは、ブループリントテンプレートが誤って上書きされないようにする場合は、他のブループリントまたは実際のアプリケーションテンプレートに同じ相対パスがないことを確認することも意味します。 複数のブループリントが同じ相対テンプレートパスを提供する場合、最初に登録されたブループリントが他のブループリントよりも優先されます。
したがって、フォルダyourapplication/admin
にブループリントがあり、テンプレート'admin/index.html'
をレンダリングする必要があり、templates
を template_folder として提供した場合は次のようになります。次のようなファイルを作成するには:yourapplication/admin/templates/admin/index.html
。 追加のadmin
フォルダーの理由は、実際のアプリケーションテンプレートフォルダー内のindex.html
という名前のテンプレートによってテンプレートが上書きされないようにするためです。
これをさらに繰り返すと、admin
という名前のブループリントがあり、このブループリントに固有のindex.html
という名前のテンプレートをレンダリングする場合は、次のようにテンプレートをレイアウトすることをお勧めします。
yourpackage/
blueprints/
admin/
templates/
admin/
index.html
__init__.py
そして、テンプレートをレンダリングする場合は、admin/index.html
を名前として使用してテンプレートを検索します。 正しいテンプレートのロードで問題が発生した場合は、EXPLAIN_TEMPLATE_LOADING
構成変数を有効にして、render_template
呼び出しごとにテンプレートを見つけるために実行する手順を出力するようにFlaskに指示します。
URLの構築
あるページから別のページにリンクする場合は、通常と同じようにurl_for()
関数を使用できます。これは、URLエンドポイントの前にブループリントの名前とドット(.
)を付けるだけです。 )::
url_for('admin.index')
さらに、ブループリントまたはレンダリングされたテンプレートの表示機能を使用していて、同じブループリントの別のエンドポイントにリンクする場合は、エンドポイントの前にドットのみを付けることで、相対リダイレクトを使用できます。
url_for('.index')
これは、たとえば、現在のリクエストが他の管理ブループリントエンドポイントにディスパッチされた場合に、admin.index
にリンクします。
エラーハンドラ
ブループリントは、Flask
アプリケーションオブジェクトと同じようにerrorhandler
デコレータをサポートしているため、ブループリント固有のカスタムエラーページを簡単に作成できます。
「404ページが見つかりません」例外の例を次に示します。
@simple_page.errorhandler(404)
def page_not_found(e):
return render_template('pages/404.html')
ほとんどのエラーハンドラーは、期待どおりに機能します。 ただし、404および405例外のハンドラーに関する警告があります。 これらのエラーハンドラーは、適切なraise
ステートメント、または別のブループリントのビュー関数でのabort
の呼び出しからのみ呼び出されます。 たとえば、無効なURLアクセスによって呼び出されることはありません。 これは、ブループリントが特定のURLスペースを「所有」していないため、アプリケーションインスタンスには、無効なURLが指定された場合に実行するブループリントエラーハンドラーを知る方法がないためです。 URLプレフィックスに基づいてこれらのエラーに対して異なる処理戦略を実行する場合は、request
プロキシオブジェクトを使用してアプリケーションレベルで定義できます。
@app.errorhandler(404)
@app.errorhandler(405)
def _handle_api_error(ex):
if request.path.startswith('/api/'):
return jsonify_error(ex)
else:
return ex
エラー処理の詳細については、カスタムエラーページを参照してください。