在金字塔中调用另一个视图

时间:2011-08-13 02:47:41

标签: python view pyramid

我的目标:在金字塔中,调用另一个可调用的视图,并在不知道有关该视图的任何详细信息的情况下获取Response对象。

在我的Pyramid应用程序中,假设我有一个使用view_config装饰器定义的视图“foo”:

@view_config(route_name="foo",
             renderer="foo.jinja2")
def foo_view(request):
    return {"whereami" : "foo!"}

现在说我想将“bar”路由到暂时执行相同操作的视图,因此它在内部调用foo_view并返回其响应:

@view_config(route_name="bar")
def bar_view(request):
   return foo_view(request)

......等等!这不起作用,因为foo_view不返回Response,其渲染器会这样做。

所以,这将有效:

@view_config(route_name="bar",
             renderer="foo.jinja2")
def bar_view(request):
    return foo_view(request)

因为它将应用与foo_view相同的渲染器。但这很糟糕,因为我现在必须通过复制渲染器值并且必须知道被调用视图的渲染器来重复自己。

所以,我希望Pyramid中有一些函数允许调用另一个view-callable并在不知道或不关心渲染方式的情况下获取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 个答案:

答案 0 :(得分:8)

是的。有一些问题

  • 没有返回响应
  • 谓词/呈现
  • 权限
  • 请求与旧请求相关联的属性

这就是为什么你不应该从视图中调用视图作为函数,除非你知道你在做什么

金字塔创建者为服务器端重定向做了很棒的工具 - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html

答案 1 :(得分:3)

我也在努力解决这个问题。我有一个使用render_to_response method的解决方案,但我确信有一种“更正确”的方法。然而,在有人发布之前,我就是这样处理的:

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)

(金字塔1.3)

这需要使用渲染器,但通过在原始视图的返回值中声明渲染器,您可以在另一个视图中检索它而不知道它是什么。我怀疑是否需要这样做是不容易找到的,因为还有其他更好的方法来完成这个解决方案解决的任务。

另一个缺点是它依赖于可调用视图的直接导入。如果可以通过路线直接查找它会很好。

答案 2 :(得分: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时,文本中会打印出来   浏览器窗格将是"这来自view_two"。 view_one视图   使用pyramid.request.Request.invoke_subrequest() API获取   来自同一应用程序中的另一个视图(view_two)的响应   什么时候执行。它是通过构建一个有一个新的请求来实现的   它知道的URL与view_two视图注册匹配,并且   通过了新的请求   pyramid.request.Request.invoke_subrequest()view_two视图   调用了callable,它返回了一个响应。 view_one视图   可调用然后只返回它从中获得的响应   view_two查看可调用。

答案 3 :(得分:2)

Pyramid文档here表示将name关键字参数从view_config中删除将导致视图由函数本身注册(而不是字符串):

  

这样的注册......意味着视图名称将是* my_view *

因此,在您的情况下,您应该可以直接使用pyramid.view.render_viewpyramid.view.render_view_to_response引用foo_view

@view_config(route_name="bar")
def bar_view(request):
    return pyramid.views.render_view_to_response(None, request, name=foo_view)

<强>更新

是的,你的权利,传递视图功能不起作用

这很有意思,但是请使用您的示例代码并将route_name应用于配置 不适合我。但是,以下示例仅为视图提供name设置路由URL 并为视图命名。以这种方式,render_view_to_response的工作方式与宣传的一样。命名, 你的观点可能不是你想要的,但这种配置与你的观点完全相同 没有添加配置的示例代码。

@view_config(name="foo")
def foo_view(request):
    # returning a response here, in lieu of having
    # declared a renderer to delegate to...
    return Response('Where am i? `{0[whereami]}'.format({"whereami" : "foo!"}))

@view_config(name="bar")
def bar_view(request):
    # handles the response if bar_view has a renderer 
    return render_view_to_response(None, request, name='foo')

@view_config(name="baz")
def baz_view(request):
    # presumably this would not work if foo_view was
    # not returning a Response object directly, as it
    # skips over the rendering part. I think you would
    # have to declare a renderer on this view in that case.
    return foo_view(request)

if __name__ == '__main__':
    config = Configurator()
    config.scan()
    app = config.make_wsgi_app()
    serve(app, host='127.0.0.1', port='5000')

答案 4 :(得分:1)

你不能做那样的事情:

@view_config(名称= “baz” 的) def baz_view(请求):     返回HTTPFound(location = self.request.route_path('foo'))

答案 5 :(得分:1)

不是您要求的精确解决方案,而是您所描述问题的解决方案:

创建一个视图类,其中foo和bar都是方法。然后bar可以调用self.foo()

可以将公共view_configuration(例如模板名称)应用于类,然后只使用视图名称来装饰每个方法。

简而言之,如果我能正确理解问题,以下内容应符合您的需求。

@view_defaults(renderer="foo.jinja2")
class WhereaboutsAreFoo(object):

    @view_config(route-name="foo")
    def foo_view(self):
        return {"whereami" : "foo!"}

    @view_config(route-name="bar")
    def bar_view(self):
        return self.foo_view()