(機械翻訳) トラバーサルについて

(または、あなたがそれを気にしなければならない理由)。

注釈

この章は、許可を得て、Rob Millerのブログ記事から適応されました。

トラバーサルは:app: Pyramid`アプリケーションがURLをコードにマップすることを可能にするterm: URL dispatch`の代替手段です。

注釈

traversalとview lookupに精通しているex-Zopeのユーザは、技術的な詳細について議論している:ref: `traversal_chapter`の章に直接スキップしたいかもしれません。この章は主に、前:term: `Pylons`の経験や経験を持つ人を対象としています。これは、トラバーサルを提供しない、別のフレームワークで経験したことです。

PylonsとRouteベースのURLマッチングを長年使ってきた人達は、app: Pyramid`を使って":term: `traversal "という新しいアイデアに初めて公開されています。 ":term:` view lookup` "は着信HTTPリクエストを呼び出し可能なコードにルーティングする方法です。同じ人の中には、トラバーサルが理解しにくいと信じている人がいます。その有用性に疑問を抱く人もいる。これまでのところ、URLマッチングが機能していたので、なぜ脳に適合せずすぐに明らかな価値を提供しない別のアプローチを検討する必要がありますか?

トラバーサルを理解したくなければ、あなたはする必要はありません。あなたは喜んで:app: Pyramid`アプリケーションを:term: URL dispatch`だけで作ることができます。しかし、パターンマッチングメカニズムよりもトラバーサルベースのアプローチではるかに簡単に処理される、単純で実用的なユースケースがいくつかあります。これらのユースケースの1つに自分自身でまだヒットしていない場合でも、これらの新しいアイデアを理解することは、いつどのWeb開発者の努力に値するのでしょうか。 :term: `Traversal`は実際には、フォルダやファイルを持つ普通のファイルシステムを使った人が簡単に理解できる単純なメタファーです。

URL派遣

私たちが解決しようとしている問題を取り上げて考えてみましょう。特定のパスに対するHTTPリクエストがWebアプリケーションにルーティングされました。要求されたパスは、アプリケーションのどこかで定義された特定の:term: `call callable`関数を呼び出す可能性があります。与えられた要求されたURLに対して、どの呼び出し可能な関数が呼び出されるべきかを決定しようとしています。

Pyramidを含む多くのシステムは、シンプルなソリューションを提供します。彼らは"URLマッチング"という概念を提供しています。 URLマッチングでは、URLパスを解析し、その結果を正規表現のセットまたは他のURLパステンプレート構文で定義された登録済みの "パターン"のセットと比較することで、この問題に近づきます。各パターンはどこかで呼び出し可能な関数にマップされます。要求パスが特定のパターンと一致する場合、関連する関数が呼び出されます。要求パスが複数のパターンと一致する場合は、競合解消スキームが使用されます。通常、最初の一致が後続の一致よりも優先されるように単純な優先順位が使用されます。要求パスが定義されたパターンのいずれとも一致しない場合、"404 Not Found "応答が返されます。

Pyramidでは、term: URL dispatch`というURLマッチングの実装を提供しています。 :app: `Pyramid`構文を使用すると、私たちのコードのどこかで定義された photo_view() 関数にマップされた / {userid} / photos / {photoid} のようなパターンがあります。 ` / joeschmoe / photos / photo1`のようなパスに対するリクエストは一致し、 `` photo_view() ``関数がリクエストを処理するために呼び出されます。同様に `` / {userid} / blog / {year} / {month} / {postid} ``は `` blog_post_view() ``関数にマップするかもしれないので、 `` / joeschmoe / blog / 2010/12 / urlmatching ``は `` urlmatching``のブログ記事をどのように見つけてレンダリングするかを知っていると思われる機能を引き起こします。

歴史的なリフレッシャー

ここでは、用語:URLのディスパッチについて理解を深めたので、トラバーサルという考え方を掘り下げます。しかし、私たちがする前に、記憶の車線を崩してみましょう。しばらくの間ウェブ作業をしてきたのであれば、term: Pylons`と:app: Pyramid`のような派手なWebフレームワークを持っていなかった時を思い出すかもしれません。代わりに、主にファイルシステムのファイルを処理する汎用HTTPサーバーがありました。特定のサイトの"root "がファイルシステム上の特定のフォルダにマップされています。リクエストURLパスの各セグメントは、サブディレクトリを表していました。最後のパスセグメントはディレクトリかファイルのいずれかであり、サーバーが適切なファイルを見つけたら、HTTP応答でそれをパッケージ化してクライアントに返します。だから、 `` / joeschmoe / photos / photo1` 'のリクエストは文字通り `` joeschmoe``フォルダのどこかに `` photos``フォルダを含み、 `` photo1``ファイル。要求されたパスに一致するフォルダやファイルが見つからない場合は、404応答を返します。

しかし、Webがよりダイナミックに成長するにつれ、少し複雑さが追加されました。 CGIやHTTPサーバモジュールなどの技術が開発されました。ファイルはまだファイルシステム上で検索されていましたが、ファイルが(例えば) `` .cgi``や `` .php``で終わった場合や、特別なフォルダにあった場合は、サーバーがファイルを読み込み、ある種のインタープリターを使用して実行し、このプロセスからの出力を最終結果としてクライアントに送信します。サーバー構成では、どのファイルが動的コードをトリガーするかを指定しました。デフォルトの場合は静的ファイルを提供するだけです。

トラバーサル(別名、リソースの場所)

信じられないかもしれませんが、ファイルシステムからのファイルの提供がどのように機能するのかを理解すれば、トラバーサルを理解することができます。そして、ある要求が指定するファイルのタイプに基づいて、サーバーが異なる何かをするかもしれないことを理解すれば、ビューの参照を理解します。

ファイルシステムのルックアップとトラバーサルの主な違いは、ファイルシステムのルックアップがファイルシステムツリーのネストされたディレクトリとファイルを辿るのに対し、:term: `リソースツリー 'のネストされたディクショナリタイプのオブジェクトをたどることです。私たちの例のパスの1つを詳細に見てみましょう。つまり、私が意味するものを見ることができます。

パス `` / joeschmoe / photos / photo1``には、 `` / `` joeschmoe、 `` photos``、 `` photo1``という4つのセグメントがあります。ファイルシステムのルックアップでは、入れ子になったフォルダ( `` joeschmoe``)を含むルートフォルダ( `` / )があり、JPGファイル( `` photos ' ``写真1)。トラバーサルでは、代わりに辞書のようなルートオブジェクトがあります。 `` joeschmoe``キーを要求すると、別の辞書のようなオブジェクトが得られます。 `` photos``キーを尋ねると、 `` photo1``キーで参照される値の中で探しているリソースが最終的に(うまくいけば)含まれている、別のマッピングオブジェクトが得られます。

純粋なPythonの言葉では、 `` / joeschmoe / photos / photo1``要求を満たすトラバーサルまたは"resource location "部分は、この疑似コード:

get_root()['joeschmoe']['photos']['photo1']

`` get_root() ``はルートトラバーサル:term: resource`を返す関数です。指定されたすべてのキーが存在する場合、返されるオブジェクトは、ファイルシステムの例で取得されたJPGファイルに類似して、要求されているリソースになります。 :exc: `KeyError`が途中で生成された場合、:app: Pyramid`は404を返します(これは正確ではありませんが、以下のビュールックアップについてはわかりますが、基本的な考え方保持します。)

"リソース"とは何ですか?

"理解しているファイルシステム上のファイル"と言うかもしれません。 "しかし、これらのネストされた辞書のものは何ですか?これらのオブジェクト、これらの 'リソース'はどこに住んでいますか?

以来、:app: Pyramid`は非常に有益なフレームワークではないので、term: resource`がどのように実装されているかに制限はありません。開発者は希望どおりに実装することができます。使用される一般的なパターンの1つは、ルートを含むすべてのリソースをデータベースにグラフとして保持することです。ルートオブジェクトは辞書のようなオブジェクトです。 Pythonの辞書のようなオブジェクトは、キーの参照が行われたときに呼び出される `` __getitem__``メソッドを提供します。フードの中で、 `` adict``が辞書のようなオブジェクトであるとき、Pythonは `` adict ['a'] ``を `` adict .__ getitem __( 'a') ``に翻訳します。あなたが私たちを信じていない場合は、Pythonインタプリタのプロンプトでこれを試してみてください:

>>> adict = {}
>>> adict['a'] = 1
>>> adict['a']
1
>>> adict.__getitem__('a')
1

辞書のようなルートオブジェクトは、すべてのサブリソースのIDをキーとして格納し、それらを取得する `` __getitem__``実装を提供します。 `` get_root()['joeschmoe'] ``はデータベースにも格納されている別のオブジェクトを返します。データベースには独自のサブリソースと `` __getitem__``があります。 `` get_root() 実装、など。これらのリソースは、最近人気を集めている多くの"NoSQL "ソリューションの1つであるリレーショナルデータベースに永続化される可能性があります。それは問題ではない。返されたオブジェクトがディクショナリのようなAPIを提供する限り(すなわち、適切に実装された ` __getitem__``メソッドを持つ限り)、トラバーサルが機能します。

実際、"データベース"は必要ありません。普通の辞書を使うことができます。サイトのURL構造はPythonソースで直接ハードコードされています。あるいは、特定のディレクトリ内のファイルを検索する `` __getitem__``メソッドでオブジェクトのセットを簡単に実装することができ、URLパスをファイルシステム上のフォルダ構造に直接マッピングする従来のメカニズムを正確に再現することができます。実際、トラバーサルはファイルシステム検索のスーパーセットです。

注釈

リソースの技術的概要については、ref: `resources_chapter`という章を参照してください。

ルックアップの表示

この時点で、我々はほぼそこにいる。ここでは、特定のURLパスに従って特定のリソースを取得するプロセスであるトラバーサルについて説明しました。しかし、"ビュールックアップ"とは何ですか?

ビューのルックアップの必要性は簡単です。:term: resource`を見つけた後に取るべきアクションは複数あります。たとえば、写真の例では、ページ内の写真を表示することができますが、ユーザーが写真や関連するメタデータを編集する方法を提供することもできます。前者を ` view``ビューと呼び、後者を `` edit``ビューと呼びます。 (オリジナル、私は知っている):app: Pyramid`は集中ビューを持っています:term: application registry`名前付きビューは特定のリソースタイプに関連付けることができます。この例では、写真オブジェクトのビューを表示していると仮定し、 `` view``ビューをデフォルトとして指定しているので、 `` / joeschmoe / photos / photo1 / view``と / joeschmoe / photos / photo1``は同等です。エディットビューは ` / joeschmoe / photos / photo1 / edit` 'のリクエストによって提供されます。

うまくいけば、編集ビューのURLパスの最初の部分が非編集バージョンと同じリソース、特に `` get_root()['joeschmoe'] ['photos'] ['写真1 '] ``。しかし、そこを横切って終わります。 `` photo1``リソースには `` edit``キーがありません。実際、辞書的なオブジェクトではないかもしれません。その場合、 `` photo1 ['edit'] ``は意味がありません。 :app: Pyramid`リソースの場所が* leaf *リソースに解決されたが、要求パス全体がまだ消費されていない場合、*非常に次の*パスセグメントは:term: view name`として扱われます。次に、指定された名前のビューが指定されたタイプのリソースに対して指定されているかどうかを調べるために、レジストリがチェックされます。もしそうなら、呼び出し可能なビューが呼び出され、リソースは関連する `` context``オブジェクトとして渡されます( `` request.context``としても利用可能です)。ビュー呼び出し可能なものが見つからなかった場合、:app: `Pyramid`は" 404 Not Found "という応答を返します。

`` / joeschmoe / photos / photo1 / edit``のリクエストを、最終的に次のPythonの擬似コードに変換するように概念化することもできます:

context = get_root()['joeschmoe']['photos']['photo1']
view_callable = get_view(context, 'edit')
request.context = context
view_callable(request)

`` get_root``と `` get_view``関数は実際には存在しません。内部的には、:app: `Pyramid`はもっと複雑なことをします。しかし、上記の例は、擬似コードにおけるビュールックアップアルゴリズムの合理的な近似である。

ユースケース

なぜトラバーサルが気になるのですか? URLマッチングは説明しやすく、十分です。

いくつかのケースでは、そうですが、必ずしもすべてではありません。これまでのところ、非常に構造化されたURLがありました。ここでは、パスには特定の少数のピースがあります:

/{userid}/{typename}/{objectid}[/{view_name}]

これまでのすべての例では、開発時にどの名前が使用されるかを知っていると仮定して、typenameの値をハードコーディングしました("写真"、"ブログ"など)。しかし、もしこれらの名前がどんなものか分からなければどうでしょうか?あるいは、さらに悪いことに、ユーザーのフォルダ内のURLの構造について何か知りません。エンドユーザーが自分のフォルダ内にコンテンツや他のフォルダを任意に追加できるようにするCMSを作成することができます。彼は数十層のフォルダを深く入れ子にすることに決めたかもしれない。どのように発展するかもしれないパスの可能な組み合わせを考慮に入れることができるマッチングパターンをどのように構築しますか?

それは可能かもしれませんが、確かに簡単ではありません。マッチするパターンは、すべてのエッジケースを処理しようとすると、すぐに複雑になります。

しかし、トラバースでは簡単です。ネスティングの20のレイヤーは問題ありません。 :app: Pyramid`は、パスセグメントがなくなるまで、またはリソースが:exc: KeyError`を呼び出すまで、必要なだけ `` __getitem__``を何度も呼び出します。各リソースは、直接の子をフェッチする方法を知る必要があり、トラバーサルアルゴリズムは残りの部分を処理します。また、リソースツリーの構造はコードではなくデータベースに存在するため、ユーザーが実行時に独自のパーソナライズされたディレクトリ構造を設定できるようにするのは簡単です。

コンテキスト依存のセキュリティポリシーをサポートする必要がある場合、トラバーサルが輝く別のユースケースです。たとえば、異なる部門のメンバーがさまざまな部門のファイルへのアクセスレベルを変える大企業のための文書管理インフラストラクチャの例があります。合理的に、特定のファイルであっても、特定の個人が利用できるようにする必要があるかもしれません。リソース認可の考え方がコード解決と呼び出しプロセスの直後に焼き付けられているため、リソースが実際に文書に関連するデータオブジェクトを表す場合、Traversalはうまくいきます。リソースオブジェクトは、サブリソースによって継承および/またはオーバーライドできるACLを格納することができます。

したがって、各リソースがコンテキストベースのACLを生成できる場合、ビューコードが機密アクションを実行しようとするたびに、そのACLに対して現在のユーザーがアクションを実行できるかどうかを確認できます。このようにして、従来の表形式の手法を使用してモデル化するのがかなり難しい、いわゆる「インスタンスベース」または「行レベル」のセキュリティを実現します。 :app: Pyramid`はこのようなスキームを積極的にサポートしています。実際にあなたのビューに保護された権限を登録し、権限ポリシーを使用すると、app: Pyramid`はビュー自体が現在のユーザーが利用できる。

要約すると、トラバーサルとビュールックアップによってより簡単に提供される問題のクラス全体が、term: URL dispatch`よりもあります。あなたの問題がそれを必要としないなら、偉大な、言葉:用語: `URLディスパッチ。しかし、あなたが:app: `Pyramid`を使っていて、これらのユースケースの1つをサポートする必要があることが判明した場合、あなたはあなたのツールキットでのトラバースをうれしく思います。

注釈

同じ:app: Pyramid`アプリケーションで、term: traversal`を:term: `URL dispatch`と組み合わせてマッチさせることも可能です。詳細については、:ref: `hybrid_chapter`の章を参照してください。