6

私は、同じプログラムとデータベーススキーマで、コンテンツが異なる複数のWebサイトを制御する管理Webサイトを作成しています。私がこのように設計したURL:

http://example.com/site                 A list of all sites which under control
http://example.com/site/{id}            A brief overview of select site with ID id
http://example.com/site/{id}/user       User list of target site
http://example.com/site/{id}/item       A list of items sold on target site
http://example.com/site/{id}/item/{iid} Item detailed information
# ...... something similar

ご覧のとおり、ほぼすべてのURLにsite_idが必要です。そして、ほとんどすべてのビューで、site_idを使用してデータベースに対してサイトモデルをクエリするなど、いくつかの一般的な作業を行う必要があります。また、request.route_pathを呼び出すたびにsite_idを渡す必要があります。

それで...とにかく私の人生を楽にするために私のためにありますか?

4

2 に答える 2

5

ハイブリッドアプローチを使用してサイトをロードすると便利な場合があります。

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拡張されます。そのルートが一致すると、ルートパターンからプレースホルダーが取得され、それがトラバーサルパス(トラバーサルツリーの構造に基づいて定義されるパス)として使用されます。configadd_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。

于 2012-11-02T15:14:37.833 に答える
3

__init__ビューの場合、クラスを使用して、メソッド(docs)で一般的なジョブを実行できるようにすることができます。

from pyramid.view import view_config

class SiteView(object):
    def __init__(self, request):
        self.request = request
        self.id = self.request.matchdict['id']
        # Do any common jobs here

    @view_config(route_name='site_overview')
    def site_overview(self):
        # ...

    @view_config(route_name='site_users')
    def site_users(self):
        # ...

    def route_site_url(self, name, **kw):
        return self.request.route_url(name, id=self.id, **kw)

また、ルートプレフィックスを使用してURLを処理することもできます(docs)。これがあなたの状況に役立つかどうかわからない。

from pyramid.config import Configurator

def site_include(config):
    config.add_route('site_overview', '')
    config.add_route('site_users', '/user')
    config.add_route('site_items', '/item')
    # ...

def main(global_config, **settings):
    config = Configurator()
    config.include(site_include, route_prefix='/site/{id}')
于 2012-11-02T10:58:14.683 に答える