对您来说,使用混合方法来获取网站可能很有用。
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
我们将使用groupfinder用户映射到主体。我们在这里选择仅将它们映射到其拥有会员资格的网站。我们简单的遍历只需要一个根对象。它更新加载的site
与__acl__
,使用相同的主体groupfinder
安装创建。
您需要在Pyramid Cookbook中设置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
前辈可以找到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__
。
程序pregenerator
每个路由与试图找到的Site
实例在遍历层次结构的请求的程序pregenerator更新。如果当前请求没有解析为基于站点的URL,这可能会失败。预生成器然后用站点ID更新发送到route_url
的关键字。
认证
的例子显示,你怎么能有这一个用户进入,表明该用户是在“网站:”校长映射认证策略组。该站点(request.context
)随后更新为具有ACL,表示如果site.id == 1
“site:1”组中的某个用户应具有“查看”权限。 users_view
然后更新为需要“查看”权限。如果用户被拒绝访问视图,这将引发HTTPForbidden
异常。如果需要,你可以编写一个异常视图来有条件地将其转换为404。
我回答的目的只是为了说明混合方法如何通过处理背景中的URL的常见部分来使您的视图更美观。 HTH。
因为我的Pyramid的遍历知识泄漏,我完全不能理解你的例子,但我会阅读文档并尝试理解它::-)顺便说一下:当我调用请求时,你的解决方案是否可以消除'site_id'参数.route_path? –
通过向生成路由时自动填充site_id的路由添加预生成器,可以消除“site_id”。这并不明显,这就是为什么我张贴它来激发你的胃口。但预先配置一些声明式配置后,您的观点可能变得非常简单。 –
我仍然陷入混乱.....你介意更新你提到的这个预生产者的例子吗?谢谢!顺便说一下,如果我想为不同的Site.type添加不同的路由,我该怎么办?例如,如果site1.type是'passport'且site1.id是1,site2.type是'www'且site2.id是2,那么/ site/1/user应映射到视图,但是/ site/2 /用户应该引发404错误。 –