ハイブリッドアプローチを使用してサイトをロードすると便利な場合があります。
def groupfinder(userid, request):
user = request.db.query(User).filter_by(id=userid).first()
if user is not None:
# somehow get the list of sites they are members
sites = user.allowed_sites
return ['site:%d' % s.id for s in sites]
class SiteFactory(object):
def __init__(self, request):
self.request = request
def __getitem__(self, key):
site = self.request.db.query(Site).filter_by(id=key).first()
if site is None:
raise KeyError
site.__parent__ = self
site.__name__ = key
site.__acl__ = [
(Allow, 'site:%d' % site.id, 'view'),
]
return site
グループファインダーを使用して、ユーザーをプリンシパルにマップします。ここでは、メンバーシップを持っているサイトにのみマップすることを選択しました。単純なトラバーサルには、ルートオブジェクトのみが必要です。作成するように設定されているのと同じプリンシパルを使用するでsite
ロードされたを更新します。__acl__
groupfinder
request.db
ピラミッドクックブックで特定のパターンを設定する必要があります。
def site_pregenerator(request, elements, kw):
# request.route_url(route_name, *elements, **kw)
from pyramid.traversal import find_interface
# we use find_interface in case we improve our hybrid traversal process
# to take us deeper into the hierarchy, where Site might be context.__parent__
site = find_interface(request.context, Site)
if site is not None:
kw['site_id'] = site.id
return elements, kw
Pregeneratorは、を見つけsite_id
てURLに自動的に追加できます。
def add_site_route(config, name, pattern, **kw):
kw['traverse'] = '/{site_id}'
kw['factory'] = SiteFactory
kw['pregenerator'] = site_pregenerator
if pattern.startswith('/'):
pattern = pattern[1:]
config.add_route(name, '/site/{site_id}/' + pattern, **kw)
def main(global_conf, **settings):
config = Configurator(settings=settings)
authn_policy = AuthTktAuthenticationPolicy('seekrit', callback=groupfinder)
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(ACLAuthorizationPolicy())
config.add_directive(add_site_route, 'add_site_route')
config.include(site_routes)
config.scan()
return config.make_wsgi_app()
def site_routes(config):
config.add_site_route('site_users', '/user')
config.add_site_route('site_items', '/items')
ここでアプリケーションをセットアップします。また、ルートをより簡単にテストできるようにする包含可能な関数にルートを移動しました。
@view_config(route_name='site_users', permission='view')
def users_view(request):
site = request.context
その後、ビューが簡略化されます。これらは、ユーザーがサイトにアクセスする権限を持っており、サイトオブジェクトが既に読み込まれている場合にのみ呼び出されます。
ハイブリッドトラバーサル
カスタムディレクティブが追加され、ルートにトラバーサルサポートが自動的に追加されるラッパーでオブジェクトがadd_site_route
拡張されます。そのルートが一致すると、ルートパターンからプレースホルダーが取得され、それがトラバーサルパス(トラバーサルツリーの構造に基づいて定義されるパス)として使用されます。config
add_route
{site_id}
/{site_id}
トラバーサルは/{site_id}
、最初のステップがツリーのルートを見つけることであるパスで発生します(/
)。SiteFactory
ルートは、トラバーサルパスのルートとしてを使用してトラバーサルを実行するように設定されています。このクラスはルートとしてインスタンス化され__getitem__
、パス()の次のセグメントであるキーを使用して呼び出されます{site_id}
。次に、そのキーに一致するサイトオブジェクトを見つけて、可能であればロードします。次に、サイトオブジェクトがとで更新され、__parent__
が機能__name__
できるようになりfind_interface
ます。また、__acl__
後述する権限を提供することで拡張されます。
プレジェネレーター
Site
各ルートは、リクエストのトラバーサル階層でのインスタンスを見つけようとするプリジェネレータで更新されます。現在のリクエストがサイトベースのURLに解決されなかった場合、これは失敗する可能性があります。次に、プレジェネレータは、送信されたキーワードをroute_url
サイトIDで更新します。
認証
この例は、ユーザーをプリンシパルにマップして、このユーザーが「site:」グループに属していることを示す認証ポリシーを設定する方法を示しています。次に、サイト( )が更新され、「site:1」グループの誰かが「表示」権限を持つ必要があるrequest.context
ことを示すACLが作成されます。site.id == 1
次にusers_view
、が更新され、「表示」権限が必要になります。これによりHTTPForbidden
、ユーザーがビューへのアクセスを拒否された場合に例外が発生します。必要に応じて、例外ビューを記述して、これを条件付きで404に変換できます。
私の答えの目的は、ハイブリッドアプローチが、バックグラウンドでURLの一般的な部分を処理することによって、ビューを少し良くする方法を示すことです。HTH。