Flaskでの設計上の決定—Flaskのドキュメント

提供:Dev Guides
< FlaskFlask/docs/1.0.x/design
移動先:案内検索

Flaskでの設計上の決定

なぜFlaskが特定のことを同じように行い、同じように行うのか興味がある場合は、このセクションが役に立ちます。 これにより、特に他のフレームワークと直接比較した場合に、最初は恣意的で意外に見える可能性のあるいくつかの設計上の決定についてのアイデアが得られるはずです。

明示的なアプリケーションオブジェクト

WSGIに基づくPythonWebアプリケーションには、実際のアプリケーションを実装する1つの中央呼び出し可能オブジェクトが必要です。 Flaskでは、これはFlaskクラスのインスタンスです。 各Flaskアプリケーションは、このクラス自体のインスタンスを作成し、それにモジュールの名前を渡す必要がありますが、Flaskがそれ自体を実行できないのはなぜですか?

このような明示的なアプリケーションオブジェクトがない場合、次のコードがあります。

from flask import Flask
app = Flask(__name__)

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

代わりに次のようになります。

from hypothetical_flask import route

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

これには3つの主な理由があります。 最も重要なのは、暗黙のアプリケーションオブジェクトでは、一度に1つのインスタンスしか存在できない必要があるということです。 アプリケーションのスタックを維持するなど、単一のアプリケーションオブジェクトで複数のアプリケーションを偽造する方法はいくつかありますが、これによりいくつかの問題が発生します。ここでは詳しく説明しません。 ここで問題となるのは、マイクロフレームワークに同時に複数のアプリケーションが必要になるのはいつかということです。 この良い例はユニットテストです。 何かをテストしたい場合は、特定の動作をテストするための最小限のアプリケーションを作成すると非常に役立ちます。 アプリケーションオブジェクトが削除されると、割り当てられたすべてのものが再び解放されます。

コード内に明示的なオブジェクトが存在する場合に可能になるもう1つのことは、基本クラス(Flask)をサブクラス化して、特定の動作を変更できることです。 オブジェクトが公開されていないクラスに基づいて事前に作成されている場合、これはハックなしでは不可能です。

しかし、Flaskがそのクラスの明示的なインスタンス化に依存するもう1つの非常に重要な理由があります。それは、パッケージ名です。 Flaskインスタンスを作成するときは常に、通常、パッケージ名として __ name __ を渡します。 Flaskはその情報に依存して、モジュールに関連するリソースを適切にロードします。 Pythonのリフレクションに対する卓越したサポートにより、パッケージにアクセスして、テンプレートと静的ファイルが保存されている場所を特定できます(open_resource()を参照)。 今では明らかに、構成を必要とせず、アプリケーションモジュールに関連するテンプレートをロードできるフレームワークがあります。 ただし、そのために現在の作業ディレクトリを使用する必要があります。これは、アプリケーションがどこにあるかを判断するための非常に信頼性の低い方法です。 現在の作業ディレクトリはプロセス全体であり、1つのプロセスで複数のアプリケーションを実行している場合(知らないうちにWebサーバーで発生する可能性があります)、パスはオフになります。 さらに悪いことに、多くのWebサーバーは、作業ディレクトリをアプリケーションのディレクトリに設定するのではなく、同じフォルダである必要のないドキュメントルートに設定します。

3番目の理由は、「暗黙的よりも明示的の方が優れている」ということです。 そのオブジェクトはWSGIアプリケーションであり、他に何も覚えておく必要はありません。 WSGIミドルウェアを適用する場合は、ラップするだけで完了です(ただし、アプリケーションオブジェクトwsgi_app()への参照が失われないようにするためのより良い方法があります)。

さらに、この設計により、ファクトリ関数を使用して、単体テストなどに非常に役立つアプリケーションを作成できます(アプリケーションファクトリ)。


ルーティングシステム

Flaskは、複雑さによってルートを自動的に順序付けるように設計されたWerkzeugルーティングシステムを使用します。 これは、ルートを任意の順序で宣言でき、それらが引き続き期待どおりに機能することを意味します。 アプリケーションが複数のモジュールに分割されている場合、デコレータは未定義の順序で起動される可能性があるため、これはデコレータベースのルーティングを適切に実装する場合の要件です。

Werkzeugルーティングシステムのもう1つの設計上の決定は、WerkzeugのルートがURLが一意であることを確認しようとすることです。 Werkzeugは、ルートがあいまいな場合に正規URLに自動的にリダイレクトするという点でかなり進んでいます。


1つのテンプレートエンジン

Flaskは、1つのテンプレートエンジンであるJinja2を決定します。 Flaskにプラグ可能なテンプレートエンジンインターフェイスがないのはなぜですか? 明らかに別のテンプレートエンジンを使用することもできますが、Flaskは引き続きJinja2を構成します。 Jinja2が常に構成されているという制限はおそらくなくなるでしょうが、1つのテンプレートエンジンをバンドルしてそれを使用するという決定はおそらくなくなります。

テンプレートエンジンはプログラミング言語のようなものであり、それらのエンジンはそれぞれ、物事がどのように機能するかについて一定の理解を持っています。 表面的には、それらはすべて同じように機能します。一連の変数を使用してテンプレートを評価し、戻り値を文字列として受け取るようにエンジンに指示します。

しかし、それは類似点が終わるところです。 たとえば、Jinja2には、広範なフィルターシステム、テンプレートの継承を行う特定の方法、テンプレート内およびPythonコードから使用できる再利用可能なブロック(マクロ)のサポート、すべての操作にUnicodeを使用、反復テンプレートレンダリング、構成可能な構文があります。もっと。 一方、Genshiのようなエンジンは、XMLストリームの評価、XPathの可用性を考慮したテンプレートの継承などに基づいています。 一方、MakoはテンプレートをPythonモジュールと同様に扱います。

テンプレートエンジンをアプリケーションまたはフレームワークに接続することになると、テンプレートをレンダリングするだけではありません。 たとえば、FlaskはJinja2の広範な自動エスケープサポートを使用しています。 また、Jinja2テンプレートからマクロにアクセスする方法も提供します。

テンプレートエンジンの独自の機能を奪わないテンプレート抽象化レイヤーは、それ自体が科学であり、Flaskのようなマイクロフレームワークには大きすぎる取り組みです。

さらに、拡張機能は、存在する1つのテンプレート言語に簡単に依存できます。 独自のテンプレート言語を簡単に使用できますが、拡張機能はJinja自体に依存する可能性があります。


依存関係のあるマイクロ

Flaskがそれ自体をマイクロフレームワークと呼ぶのに、2つのライブラリ(つまり、WerkzeugとJinja2)に依存しているのはなぜですか。 なぜそうすべきではないのですか? Web開発のRuby側に目を向けると、WSGIと非常によく似たプロトコルがあります。 そこにはRackと呼ばれていますが、それ以外はRubyのWSGIレンディションに非常によく似ています。 ただし、Rubyランドのほぼすべてのアプリケーションは、Rackで直接動作するのではなく、同じ名前のライブラリ上で動作します。 このRackライブラリには、Pythonで2つの同等のものがあります。WebOb(以前のPaste)とWerkzeugです。 貼り付けはまだありますが、私の理解では、WebObを支持して非推奨になっています。 WebObとWerkzeugの開発は、同様のアイデアを念頭に置いて並行して開始されました。他のアプリケーションが利用できるように、WSGIの優れた実装である必要があります。

Flaskは、Werkzeugがすでに行った作業を利用して、WSGIを適切にインターフェースするフレームワークです(これは、複雑なタスクになる場合があります)。 Pythonパッケージインフラストラクチャの最近の開発のおかげで、依存関係のあるパッケージはもはや問題ではなく、他の人に依存するライブラリを持つことに反対する理由はほとんどありません。


スレッドローカル

Flaskは、リクエスト、セッション、および独自のものを配置できる追加のオブジェクト( g )に、スレッドローカルオブジェクト(実際にはコンテキストローカルオブジェクト、グリーンレットコンテキストもサポートします)を使用します。 それはなぜですか、それは悪い考えではありませんか?

はい、通常、スレッドローカルを使用することはそれほど賢明な考えではありません。 スレッドの概念に基づかないサーバーに問題を引き起こし、大規模なアプリケーションの保守を困難にします。 ただし、Flaskは大規模なアプリケーションや非同期サーバー向けには設計されていません。 Flaskは、従来のWebアプリケーションをすばやく簡単に作成できるようにしたいと考えています。

また、Flaskに基づく大規模なアプリケーションのインスピレーションについては、ドキュメントの Becoming Big セクションを参照してください。


フラスコとは何か、フラスコとは何か

Flaskにデータベースレイヤーが含まれることはありません。 フォームライブラリなど、その方向にあるものはありません。 Flask自体は、適切なWSGIアプリケーションを実装するためにWerkzeugに、テンプレートを処理するためにJinja2にブリッジするだけです。 また、ロギングなどのいくつかの一般的な標準ライブラリパッケージにもバインドします。 他のすべては拡張のためにあります。

なぜそうなのですか? なぜなら、人々はさまざまな好みや要件を持っており、Flaskは、これをコアに強制する場合、それらを満たすことができなかったからです。 Webアプリケーションの大部分は、何らかのテンプレートエンジンを必要とします。 ただし、すべてのアプリケーションにSQLデータベースが必要なわけではありません。

Flaskのアイデアは、すべてのアプリケーションの優れた基盤を構築することです。 他のすべてはあなたまたは拡張機能次第です。