在Pyramid中调用另一个视图
我的目标是:在Pyramid框架中,调用另一个视图,并获取一个Response
对象,而不需要了解这个视图的任何细节。
在我的Pyramid应用中,假设我有一个名为"foo"的视图,它是通过一个叫做view_config的装饰器定义的:
@view_config(route_name="foo",
renderer="foo.jinja2")
def foo_view(request):
return {"whereami" : "foo!"}
现在假设我想把"bar"路由到一个视图,这个视图暂时做同样的事情,所以它内部调用foo_view
并返回它的Response:
@view_config(route_name="bar")
def bar_view(request):
return foo_view(request)
……但是等一下!这样做不行,因为foo_view
并不直接返回一个Response
,而是它的renderer返回。
所以,这样做是可行的:
@view_config(route_name="bar",
renderer="foo.jinja2")
def bar_view(request):
return foo_view(request)
因为它会应用和foo_view
一样的renderer。但这样不好,因为我现在必须重复自己,既要复制renderer的值,还要知道被调用视图的renderer是什么。
所以,我希望在Pyramid中有一个函数,可以调用另一个视图并获取一个Response
对象,而不需要知道或关心它是如何渲染的:
@view_config(route_name="bar")
def bar_view(request):
response = some_function_that_renders_a_view_callable(foo_view, request)
return response
那么some_function_that_renders_a_view_callable
会是什么呢?
pyramid.views.render_view
似乎是通过名称查找视图;但我不想给我的视图起名字。
(注意:我想避免返回HTTPFound来让客户端重定向到目标路由。我想要的是“内部”重定向。)
6 个回答
我也遇到过这个问题。我有一个解决方案,使用的是render_to_response 方法,不过我相信还有“更正确”的做法。不过在有人分享之前,我就先把我的处理方法告诉你:
from pyramid.renderers import render_to_response
@view_config(route_name="foo", renderer="foo.mak")
def foo_view(request):
return {'stuff':'things', '_renderer':'foo.mak')
def bar_view(request):
values = foo_view(request)
renderer = values['_renderer']
return render_to_response(renderer,values)
(Pyramid 1.3)
这个方法需要用到一个渲染器,但通过在原始视图的返回值中声明这个渲染器,你可以在另一个视图中获取它,而不需要知道它具体是什么。我猜这个方法不容易被找到,是因为还有其他更好的方法可以解决这个问题。
另外一个不足之处是,它依赖于直接导入视图的可调用对象。如果能通过路由直接查找就好了。
你可以通过使用 request.invoke_subrequest
来调用一个视图:
from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.request import Request def view_one(request): subreq = Request.blank('/view_two') response = request.invoke_subrequest(subreq) return response def view_two(request): request.response.body = 'This came from view_two' return request.response if __name__ == '__main__': config = Configurator() config.add_route('one', '/view_one') config.add_route('two', '/view_two') config.add_view(view_one, route_name='one') config.add_view(view_two, route_name='two') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()`
当你在浏览器中访问
/view_one
时,浏览器显示的内容会是 "This came from view_two"。这里的view_one
视图使用了pyramid.request.Request.invoke_subrequest()
这个功能,去获取另一个视图 (view_two
) 的响应。它是通过构造一个新的请求来实现的,这个请求的 URL 是它知道可以匹配view_two
的注册信息,然后把这个新请求传递给pyramid.request.Request.invoke_subrequest()
。接着,view_two
视图被调用,并返回了一个响应。最后,view_one
视图就简单地返回了它从view_two
视图得到的响应。
没错,这里有一些需要注意的地方:
- 它不会返回一个响应
- 涉及到条件和渲染器
- 权限问题
- 与旧请求相关的请求属性
所以,除非你知道自己在做什么,不然不要在视图中像调用函数一样去调用另一个视图。
Pyramid的开发者为服务器端重定向提供了一个很棒的工具 - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html