リソース¶
resource は、アプリケーションに関係付けられたツリー上の「場所」 を表わすオブジェクトです。すべての Pyramid アプリケーションには 少なくとも 1 つのリソースオブジェクトがあります: root リソースです。 あなたが root リソースを手動で定義しなかったとしても、デフォルトの root リソースが自動的に作成されます。 root リソースは resource tree の根です。リソースツリーは入れ子の辞書風オブジェクトの集まりで、 ウェブサイトの構造を表わすために使用することができます。
URL をコードにマッピングするために traversal を使用するアプリ ケーションでは、リソースツリー構造は各 URL を view callable に マッピングするために頻繁に使用されます。 traversal が使用されて いる時、 Pyramid は context リソースを見つけるために、 入れ子の辞書構造をトラバースすることによってリソースツリーを渡り歩きます。 コンテキストリソースが見つかれば、 view callable を見つける ためにコンテキストリソースとリクエスト中のデータが使用されます。
URL dispatch を使用するアプリケーションでは、リソースツリーは 間接的にのみ使用され、開発者からは多くの場合「見えないもの」です。 URL ディスパッチアプリケーションでは、リソース「ツリー」は、しばしば root リソース自身のみから構成されます。この root リソースには、セキュリティ 宣言が取り付けられることがありますが、常にそうすることは要求されません。 一般に、トラバーサルを使用するアプリケーションに比べて URL ディスパッチを 使用するアプリケーションにおいてリソースツリーはそれほど重要ではありません。
「Zope 風」の Pyramid アプリケーションではさらに、リソースオブジェクト はしばしばデータを永続的に格納します。そして、その永続的なデータを変化 させることに関係するメソッドを提供します。この種類のアプリケーションでは、 リソースはウェブサイトのサイト構造を表わすだけでなく、アプリケーションの domain model になります。
さらに、
add_view()
(あるいはview_config()
デコレータ) に対するcontext
およびcontainment
述語引数は、 リソースクラスまたはリソース interface を参照します。
- root factory はリソースを返します。
- 種々の有用な Pyramid API メソッドは、引数としてリソースを期待します
(例えば
resource_url()
など)。
リソースツリーを定義する¶
traversal が使用されている場合 (純粋に url dispatch に
基づいたアプリケーションとは対照的に)、 Pyramid はリソースから
構成されるツリー (resource tree)をトラバースできることを期待します。
トラバースは root リソースから始まり、別のリソースオブジェクトへのパス
セグメントを解決するために各リソースの __getitem__
メソッドを試しながら、
ツリーを再帰的に下って行きます。 Pyramid はツリー上のリソース
インスタンスに以下のポリシーを課します:
- コンテナリソース (他のリソースを含むリソース) は、サブリソースへの
unicode 名を解決するための
__getitem__
メソッドを提供しなければ なりません。特定の名前のサブリソースがコンテナリソースに存在しない場合、 コンテナリソースの__getitem__
メソッドはKeyError
を 投げげなければなりません。その名前のサブリソースが存在する場合、コンテナの__getitem__
はサブリソースを返す必要があります。
- リーフリソース (他のリソースを含まないリソース) は
__getitem__
を 実装してはなりません。あるいは、実装する場合__getitem__
メソッドは 常にKeyError
を上げなければなりません。
トラバーサルがリソースインスタンスに対してどのように動作するかについての 詳細は Traversal を参照してください。
これは root
という名前の変数で表わされるサンプルのリソースツリーです:
1 2 3 4 | class Resource(dict):
pass
root = Resource({'a':Resource({'b':Resource({'c':Resource()})})})
|
上で作成したリソースツリーは、 'a'
という名前の子供を持つ辞書風の
root オブジェクトによって表わされます。 'a'
は、 'b'
という名前の
単一の子供を持っています。また、 'b'
は 'c'
という名前の単一の子供を
持っています。 'c'
は子供を持っていません。そのため、次のようにして
'c'
リーフリソースにアクセスすることが可能です:
1 | root['a']['b']['c']
|
もし root factory から上記の root
オブジェクトを返せば、
パス /a/b/c
は traversal の結果としてリソースツリー上に
'c'
オブジェクトを見つけるでしょう。
この例において、ツリーの各々のリソースは同じクラスです。これは必須では ありません。ツリーのリソース要素は任意の型になることができます。私たちは、 単純性のためにツリーのすべてのリソースを表わすために単一のクラスを使用 しました。しかし、「実際の」アプリでは、ツリーのリソースは任意のクラスが 可能です。
上記のサンプルのツリーはトラバーサルを実行することができますが、上記の 例におけるリソースインスタンスは location aware ではありません。 したがって、「実際の」アプリケーションでの有用性は制限されています。 内蔵の Pyramid API 機能を最良に利用するために、リソースは 「location-aware (位置を意識)」すべきです。次のセクションは、リソースを location-aware にする方法を詳しく説明します。
location aware なリソース¶
適切な Pyramid ロケーション、セキュリティ、 URL 生成および
トラバーサル API がリソースツリー上のリソースに対して適切に働くために、
ツリー上のすべてのリソースは location -aware である必要があります。
これは、それらのリソースが __parent__
と __name__
という 2 つの
属性を持っている必要があるということを意味します。
location-aware なリソースの __parent__
属性は、そのリソースのツリー
上の親リソースインスタンスへの参照でなければなりません。 __name__
属性はリソースの親が __getitem__
によってそのリソースを参照する時の
名前でなければなりません。
root リソースの __parent__
は None
でなければなりません。また、
その __name__
は空文字列でなければなりません。例えば:
1 2 3 | class MyRootResource(object):
__name__ = ''
__parent__ = None
|
root リソースの __getitem__
メソッドから返されたリソースは、 root
リソースへの参照である __parent__
属性を持っていなければなりません。
また、その __name__
属性は、 root リソースの __getitem__
によって
到達可能な名前と一致しなければなりません。 root リソース内のコンテナリ
ソースは、コンテナを指す __parent__
属性を備えたリソースを返す
__getitem__
を持たなければなりません。また、これらのサブオブジェクトは、
__getitem__
によってコンテナから検索される名前と一致する __name__
属性を持たなければなりません。このパターンは、 root から木を「上に」
再帰的に継続します。
各リソースの __parent__
属性は、 root に向かって「下方へ」指すリンク
リストを形成します。これはファイルシステムのディレクトリ中の .. エントリ
と類似しています。リソースツリーの任意のリソースから __parent__
値
を追って行けば、やがて root リソースに達するでしょう。ちょうど、ファイル
システムコマンド cd ..
を実行し続けるといずれファイルシステムのルート
ディレクトリーに達するように。
Warning
root リソースが None
または空文字列でない __name__
引数を
持っていると、 resource_url()
関数に
よって返された URLおよび resource_path()
と
resource_path_tuple()
API によって生成された
パスは、不適当に生成されるでしょう。 __name__
の値は、生成された
すべてのパスおよび URL に前置されます (単一の先頭のスラッシュあるいは
空のタプル要素とは対照的に)。
ツリーをたどるための Pyramid API を使用するアプリケーションは
location-aware なリソースを必要とします。これらの API は、以下のもの
を含んでいます (しかしこれだけに限りません):
resource_url()
,
find_resource()
,
find_root()
,
find_interface()
,
resource_path()
,
resource_path_tuple()
, あるいは
traverse()
, virtual_root()
,
そして (通常は) has_permission()
と
principals_allowed_by_permission()
.
一般に、非常に多くの Pyramid 基盤が location-aware なリソースに 依存しているので、ツリーに含まれる各リソースを location-aware にすることは 良い考えです。
リソースの URL を生成する¶
リソースが location aware である場合、リソース用の URL を生成す
るために pyramid.request.Request.resource_url()
API を使用することが
できます。この URL は、リソースパスを生成するためにリソースの親ツリー
における位置を使用します。また、それは、スキーム、ホスト、ポートおよび
パスを持つ完全修飾 URLを形成するためにパスの前に現在のアプリケーション
URL を付けます。さらに、生成された URL に影響を及ぼすために追加の引数を
resource_url()
へ渡すことができます。
resource_url()
への最も単純な呼び出しは
このようになります:
1 | url = request.resource_url(resource)
|
上記の例で request
は Pyramid request オブジェクトの
インスタンスです。
上記の例で resource
として参照されるリソースが root リソースで、
サーバにコンタクトするために使用されたホストが example.com
だった場合、
生成される URL は http://example.com/
になります。しかし、もしリソースが
a
という名前の root リソースの子供なら、生成される URL は
http://example.com/a/
になります。
resource_url()
を使用してこの単純な方法で
リソース URL を生成する場合、すべてのリソース URL にはスラッシュが追加
されます。なぜなら、リソースは階層における「場所」であり、 URL はそこを
訪れるためにクリックされるべきものだからです。リソースのデフォルトビュー
の結果としてレンダリングされた HTML ページに含まれる相対 URL は、
その親に対してではなく、そのリソースに対して相対的であることが適切です。
さらに、追加の要素を resource_url()
へ
渡すことができます:
1 | url = request.resource_url(resource, 'foo', 'bar')
|
上記の例で resource
として参照されるリソースが root リソースで、
サーバにコンタクトするために使用されたホストが example.com
だった場合、
生成される URL は http://example.com/foo/bar
になります。任意の数の追加
の要素を追加の位置引数として resource_url()
に渡すことができます。追加の要素が渡された場合、それらはリソースの URL
に追加されます。要素が渡された場合、最終セグメントにスラッシュは追加さ
れません。
さらに、クエリ文字列を渡すこともできます:
1 | url = request.resource_url(resource, query={'a':'1'})
|
上記の例で resource
として参照されるリソースが root リソースで、
サーバにコンタクトするために使用されたホストが example.com
だった場合、
生成される URL は http://example.com/?a=1
になります。
virtual root が有効な場合、
resource_url()
によってリソースのために
生成された URL は、その物理的なツリーパスより「短い」ことがあります。
リソースの仮想的な root 変更についての詳細は
Virtual Root Support を参照してください。
リソース URL の生成に関する詳細は
pyramid.request.Request.resource_url()
のドキュメンテーションを
参照してください。
リソース URL 生成のオーバーライド¶
リソースオブジェクトが __resource_url__
メソッドを実装していれば、
このリソース用に URL を生成するために
resource_url()
が呼ばれる時、
resource_url()
によって返されるデフォルト
URL をオーバーライドしてこのメソッドが呼ばれます。
__resource_url__
フックには request
と info
という 2 つの引数
が渡されます。 request
は resource_url()
に渡された request オブジェクトです。 info
は 2 つのキーを持つ辞書です
(訳注: 「3 つ」の間違い?):
physical_path
そのリソースのために計算された「物理的パス」を表わす文字列。pyramid.traversal.resource_path(resource)
によって定義されます。 スラッシュで始まりスラッシュで終わります。
virtual_path
そのリソースのために計算された「仮想的パス」を表わす文字列。 Virtual Root Support によって定義されます。 仮想 root 変更が有効でなければ、これは物理的パスと同一でしょう。 スラッシュで始まりスラッシュで終わります。
app_url
request.resource_url
の中で生成されたアプリケーション URL を 表わす文字列。スラッシュで終わりません。これは、潜在的にカスタマイズ された URL 接頭辞を表し、ユーザによってrequest.resource_url
に 渡されたカスタムなスキーム、ホストおよびポート情報を潜在的に含みます。request.application_url
よりもこちらを使用することが推奨されます。
リソースの __resource_url__
メソッドは、 URL を表わす文字列を返す
必要があります。デフォルトをオーバーライドできない場合 None
を返すべきです。
このメソッドが None
を返せば、デフォルト URL が返されるでしょう。
これはサンプルの __resource_url__
メソッドです。
1 2 3 | class Resource(object):
def __resource_url__(self, request, info):
return info['app_url'] + info['virtual_path']
|
上記の例は、実際には単にデフォルトの URL を生成して返します。それは
デフォルトの resource_url
機構によって生成されたはずのものです。
しかし、このコードは必要に応じて任意のロジックを実行できます。例えば、
あなたのコードでは、生成された URL のホスト名またはポート番号を無視
したいと思うかもしれません。
resource_url()
とともに働くために、
__resource_url__
によって生成される URL は、完全修飾形式で、
スラッシュで終わり、クエリ文字列あるいはアンカー要素を含むべきでない
(パス要素だけ)ということに注意してください。
リソースへのパスの生成¶
pyramid.traversal.resource_path()
は、リソースツリー上の位置
に基づいてリソースオブジェクトの絶対的な物理的パスを表わす文字列オブジェクト
を返します。パスのセグメントはそれぞれスラッシュ文字で分離されています。
1 2 | from pyramid.traversal import resource_path
url = resource_path(resource)
|
もし上記の例で resource
がツリー上で root['a']['b']
として
アクセス可能ならば、上記の例は文字列 /a/b
を生成するでしょう。
resource_path()
に渡されたすべての位置引数も
リソースパスの末端にパスセグメントとして追加されます。
1 2 | from pyramid.traversal import resource_path
url = resource_path(resource, 'foo', 'bar')
|
もし上記の例で resource
がツリー上で root['a']['b']
として
アクセス可能なら、上記の例は文字列 /a/b/foo/bar
を生成するでしょう。
渡されたリソースは location aware でなければなりません。
virtual root が存在するかどうかは
resource_path()
の振る舞いに影響を及ぼしません。
パスからリソースを見つける¶
リソースへの文字列パスを持っていれば、
pyramid.traversal.find_resource()
を使ってアプリケーションの
リソースツリー場所からリソースを取得することができます。
/
プリフィックスを持った文字列を path
引数として渡すことによって、
絶対パスを解決することができます:
1 2 | from pyramid.traversal import find_resource
url = find_resource(anyresource, '/path')
|
あるいは、 /
プリフィックスを持たない文字列を渡すことにより、
指定したリソースからの相対パスを解決することができます:
1 2 | from pyramid.traversal import find_resource
url = find_resource(anyresource, 'path')
|
find_resource()
に渡すパスはしばしば
resource_path()
API によって生成されます。
これらの API は互いの「鏡」です。
find_resource()
を呼び出したときにパスを解決
できなければ (ツリー上のそれぞれのリソースが存在しなければ) 、
KeyError
例外が投げられます。
パスからリソースへの解決に関する詳細は
pyramid.traversal.find_resource()
ドキュメンテーションを参照して
ください。
リソースの lineage の取得¶
pyramid.location.lineage()
は、 location aware な
resource オブジェクトの lineage (系統, 血統) を表わす
ジェネレータを返します。
lineage()
関数は渡されたリソースを返し、その後
順番にリソースの親をそれぞれ返します。例えば、リソースツリーが以下の
ように構成される場合:
1 2 3 4 5 | class Thing(object): pass
thing1 = Thing()
thing2 = Thing()
thing2.__parent__ = thing1
|
lineage(thing2)
の呼び出しはジェネレータを返します。それをリストに
変換すると、次のような結果を得るでしょう:
1 2 | list(lineage(thing2))
[ <Thing object at thing2>, <Thing object at thing1> ]
|
lineage()
によって返されたジェネレータは、最初に
渡されたリソースを無条件に返します。次に、そのリソースが
__parent__
属性を持っている場合、 resource.__parent__
によって
表わされるリソースを返します。もし その リソースが __parent__
属性
を持っている場合、そのリソースの親を返します。検査されているリソースが
__parent__
属性を持たないか、 __parent__
属性が None
になる
までこれが続きます。
詳細は、 pyramid.location.lineage()
のドキュメンテーションを参照
してください。
リソースが別のリソースの lineage かどうかの判断¶
あるリソースが別のリソースの lineage であるかどうかを判断するには、
pyramid.location.inside()
関数を使用してください。
例えば、リソースツリーがこのような場合:
1 2 3 4 5 | class Thing(object): pass
a = Thing()
b = Thing()
b.__parent__ = a
|
b
は a
を含む lineage を持つので、 inside(b, a)
の呼び出しは
True
を返すでしょう。しかし、 a
は b
を含む lineage を持たない
ので、 inside(a, b)
の呼び出しは False
を返すでしょう。
inside()
の引数リストは (resource1,
resource2)
です。 resource2
が resource1
の lineage
祖先である場合、 resource1
は resource2
の inside です。その親
(あるいはその親の親などのうちの1つ) が祖先ならば、それは lineage 祖先です。
詳細は、 pyramid.location.inside()
を参照してください。
root リソースを見つける¶
root リソースを見つけるためには
pyramid.traversal.find_root()
API を使用してください。この root
リソースは resource tree の root リソースです。この API は単一
の引数 resource
を受け取ります。 resource
は location aware
なリソースです。ツリー上で root を見つけたいと思う任意のリソースを渡す
ことができます。
例えば、リソースツリーが次のような場合:
1 2 3 4 5 | class Thing(object): pass
a = Thing()
b = Thing()
b.__parent__ = a
|
find_root(b)
の呼び出しは a
を返すでしょう。
root リソースは view callable コード内では request.root
として
もアクセス可能です。
virtual root の有無は find_root()
の
振る舞いに影響を及ぼしません。返された root オブジェクトは常に
物理的な root オブジェクトです。
インタフェースを実装するリソース¶
リソースは任意で interface を実装するように作ることができます。
インタフェースはリソースオブジェクトに「型」を用いてタグ付けするために
使用されます。型は、その後 view configuration の内で参照することが
でき、 pyramid.traversal.find_interface()
によって参照されることがで
きます。
view configuration ステートメント内の context
または
containment
述語引数としてクラスの代わりにインタフェースを指定する
ことで、単一のビュー callable をリソースオブジェクトの複数のクラスに対して
使用することができます。これをしたい理由が分からないくらいにあなたの
アプリケーションが単純な場合、このセクションを読むのをスキップできます。
例えば、これはブログエントリについて記述するコードで、ブログエントリが interface を実装すると宣言しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import datetime
from zope.interface import implementer
from zope.interface import Interface
class IBlogEntry(Interface):
pass
@implementer(IBlogEntry)
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
self.body = body
self.author = author
self.created = datetime.datetime.now()
|
このリソースは 2 つのものから構成されます: BlogEntry
クラスという
リソースコンストラクタを定義するクラスと、唯一の引数として
IBlogEntry
インタフェースを用いてクラスデコレータ implementer
によってクラスに取り付けられた interface です。
使用されるインタフェースオブジェクトは zope.interface.Interface
から継承するクラスのインスタンスでなければなりません。
リソースクラスは 0 個以上のインタフェースを実装することができます。
クラスデコレータとして zope.interface.implementer()
関数を使用する
ことにより、リソースがインタフェースを実装することを明示します。
上記の BlogEntry
リソースは IBlogEntry
インタフェースを実装
しています。
さらに、クラスではなく特定のリソース インスタンス がインタフェースを
提供することを明示することもできます。クラスがインタフェースを実装する
と宣言した場合、そのクラスのすべてのインスタンスもそのインタフェースを
提供するようになります。しかし、単一のオブジェクトがインタフェースを
提供すると単に言うこともできます。そのためには
zope.interface.directlyProvides()
関数を使用してください:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import datetime
from zope.interface import directlyProvides
from zope.interface import Interface
class IBlogEntry(Interface):
pass
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
self.body = body
self.author = author
self.created = datetime.datetime.now()
entry = BlogEntry('title', 'body', 'author')
directlyProvides(entry, IBlogEntry)
|
zope.interface.directlyProvides()
は、それ以前にインスタンスによって
提供されていた既存のあらゆるインタフェースを置き換えます。リソースオブジェクト
が既にインスタンスレベルのインタフェース宣言をしていて置き換えたくない
場合は、 zope.interface.alsoProvides()
関数を使用してください:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import datetime
from zope.interface import alsoProvides
from zope.interface import directlyProvides
from zope.interface import Interface
class IBlogEntry1(Interface):
pass
class IBlogEntry2(Interface):
pass
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
self.body = body
self.author = author
self.created = datetime.datetime.now()
entry = BlogEntry('title', 'body', 'author')
directlyProvides(entry, IBlogEntry1)
alsoProvides(entry, IBlogEntry2)
|
zope.interface.alsoProvides()
は、
zope.interface.directlyProvides()
のようにインスタンスによって
直接提供されるインタフェースの集合を上書きする代わりに、追加します。
ビュー設定でリソースインタフェースがどのように使用されるかについての 詳細は Using Resource Interfaces In View Configuration を参照してください。
クラスまたはインタフェースを使って lineage からリソースを見つける¶
特定の Python クラスの、あるいは特定の interface を実装する
親を見つけるには find_interface()
API を
使用してください。
例えば、リソースツリーが以下のように構成される場合:
1 2 3 4 5 6 | class Thing1(object): pass
class Thing2(object): pass
a = Thing1()
b = Thing2()
b.__parent__ = a
|
a
がクラス Thing1
なので、 find_interface(a, Thing1)
の呼び
出しは a
リソースを返すでしょう (最初の引数として渡されたリソースが
最初に考慮され、クラスまたはインタフェースのスペックが一致する場合それが
返されます)。
a
がクラス Thing1
で、 b
の lineage の中で a
がこのクラス
の最初のリソースなので、 find_interface(b, Thing1)
の呼び出しは
a
リソースを返すでしょう。
find_interface(b, Thing2)
の呼び出しは b
リソースを返すでしょう。
find_interface への第 2 引数は、クラスの代わりに interface を 使うことも可能です。これがインタフェースの場合、 lineage 中のそれぞれ のリソースが指定されたインタフェースを実装するかどうかチェックされます (リソースがあるクラスかどうか確かめる代わりに)。 インタフェースを実装するリソース も参照してください。
リソースに対して動作する Pyramid API 関数群¶
リソースオブジェクトはビューに提供される context として使用され ます。リソースオブジェクトがどのようにしてコンテキストになるかについて の詳細は Traversal と URL Dispatch を参照 してください。
pyramid.traversal によって提供される API は、リソースオブジェクト に対して使用されます。これらの関数は、リソースの「パス」やリソースツリー の root リソースを見つけるために、あるいはリソース用の URL を生成するた めに使用することができます。
pyramid.location によって提供される API は、リソースに対して使用 されます。これらは、リソースツリーを下へたどるか、あるいは別のリソース の「内部」のリソースを簡単に見つけるために使用することができます。
pyramid.security 中のいくつかの API は、パラメータとしてリソース
オブジェクトを受け取ります。例えば
has_permission()
API は引数の 1 つとしてリソース
オブジェクトを受け取ります; ACL がこのリソースあるいはその先祖のうちの
1 つから得られます。 pyramid.security
モジュール中の他の API も
引数として context を受け取ります。そしてコンテキストは常に
リソースです。