在Pyramid中调用另一个视图

17 投票
6 回答
7995 浏览
提问于 2025-04-16 23:31

我的目标是:在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 个回答

4

我也遇到过这个问题。我有一个解决方案,使用的是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)

这个方法需要用到一个渲染器,但通过在原始视图的返回值中声明这个渲染器,你可以在另一个视图中获取它,而不需要知道它具体是什么。我猜这个方法不容易被找到,是因为还有其他更好的方法可以解决这个问题。

另外一个不足之处是,它依赖于直接导入视图的可调用对象。如果能通过路由直接查找就好了。

6

你可以通过使用 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 视图得到的响应。

11

没错,这里有一些需要注意的地方:

  • 它不会返回一个响应
  • 涉及到条件和渲染器
  • 权限问题
  • 与旧请求相关的请求属性

所以,除非你知道自己在做什么,不然不要在视图中像调用函数一样去调用另一个视图。

Pyramid的开发者为服务器端重定向提供了一个很棒的工具 - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html

撰写回答