调用 Pyramid 中的另一个视图

发布于 2024-11-29 03:48:47 字数 1247 浏览 2 评论 0原文

我的目标:在 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 中有一些可用的函数,允许调用另一个可调用视图并返回一个 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 导致客户端重定向到目标路由是我试图避免的。我想“内部”重定向)。

My goal: In Pyramid, to call another view-callable, and to get a Response object back without knowing any details about that view-callable.

In my Pyramid application, say I have a view "foo" which is defined using a view_config decorator:

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

Now say that I want to route "bar" to a view that does the same thing for the time being, so it internally calls foo_view and returns its Response:

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

...but wait! That doesn't work, since foo_view doesn't return a Response, its renderer does.

So, this will work:

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

as it will apply the same renderer as foo_view did. But this is bad, as I now must repeat myself by copying the renderer value AND having to know the renderer of the view being called.

So, I am going to hope that there is some function available in Pyramid that allows calling another view-callable and getting a Response object back without knowing or caring how it was rendered:

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

What would some_function_that_renders_a_view_callable be?

pyramid.views.render_view appears to search for a view by name; I don't want to give my views names.

(Note: Returning HTTPFound to cause the client to redirect to the target route is what I am trying avoid. I want to "internally" redirect).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

请止步禁区 2024-12-06 03:48:48

是的。有一些问题

  • 不会返回
  • 响应谓词/渲染器
  • 权限
  • 与旧请求关联的

请求属性这就是为什么您不应该从视图中调用视图作为函数,除非您知道自己在做什么

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

Yep. There is some concerns

  • doesn't return a Response
  • predicates/renderer
  • permissions
  • request properties associated to old request

Thats why you should not call view from view as function, unless you know what you doing

Pyramid creators did awesome tool for server side redirect - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html

未央 2024-12-06 03:48:48

您可以使用 request.invoke_subrequest

from wsgiref.simple_server import make_server

从pyramid.config导入配置器

从pyramid.request导入请求


def view_one(请求):

    subreq = Request.blank('/view_two')
    响应 = request.invoke_subrequest(subreq)
    返回响应

def view_two(请求):

    request.response.body = '这来自 view_two'
    返回请求.响应

如果 __name__ == '__main__':

    配置=配置器()
    config.add_route('one', '/view_one')
    config.add_route('二', '/view_two')
    config.add_view(view_one,route_name='one')
    config.add_view(view_two,route_name='two')
    应用程序 = config.make_wsgi_app()
    服务器 = make_server('0.0.0.0', 8080, 应用程序)
    server.serve_forever()`

当在浏览器中访问 /view_one 时,打印在
浏览器窗格将是“这来自 view_two”。 view_one 视图
使用pyramid.request.Request.invoke_subrequest() API获取
来自同一应用程序中另一个视图 (view_two) 的响应
当它执行时。它通过构造一个新请求来实现这一点,该请求具有
它知道与 view_two 视图注册相匹配的 URL,以及
将新请求传递给
pyramid.request.Request.invoke_subrequest()view_two 视图
callable 被调用,并且它返回了一个响应。 view_one 视图
callable 然后简单地返回从
view_two 视图可调用。

You can invoking a view with using 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()`

When /view_one is visted in a browser, the text printed in the
browser pane will be "This came from view_two". The view_one view
used the pyramid.request.Request.invoke_subrequest() API to obtain a
response from another view (view_two) within the same application
when it executed. It did so by constructing a new request that had a
URL that it knew would match the view_two view registration, and
passed that new request along to
pyramid.request.Request.invoke_subrequest(). The view_two view
callable was invoked, and it returned a response. The view_one view
callable then simply returned the response it obtained from the
view_two view callable.

友欢 2024-12-06 03:48:48

我也在为此苦苦挣扎。我有一个使用 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)

金字塔 1.3)

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

另一个缺点是它依赖于可调用视图的直接导入。如果能直接通过路由查找就好了。

I was struggling with this as well. I have a solution using the render_to_response method, though I'm sure there's a "more correct" way to do it. Until someone posts it, however, here is how I handled this:

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)

This requires a renderer to be used, but by declaring that renderer in the original view's return values, you can retrieve it in another view without knowing what it is. I'm suspecting the need to do this isn't easily findable because there's other, better methods for accomplishing tasks solved by this solution.

Another shortcoming is that it relies on direct import of the view callable. It would be nice if it could be looked up directly by route.

铃予 2024-12-06 03:48:48

金字塔文档 here 表示将 name 关键字参数保留在 view_config 之外将导致视图由函数本身(而不是字符串)注册:

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

因此,在您的情况下,您应该能够使用 pyramid.view.render_viewpyramid.view.render_view_to_response code> 直接引用 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')

The Pyramid documentation here indicates that leaving the name key word argument out of view_config will cause the view to be registered by the function itself (rather than a string):

Such a registration... implies that the view name will be *my_view*

So, in your case you should be able to use pyramid.view.render_view or pyramid.view.render_view_to_response referencing foo_view directly:

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

Update:

Yep, your right, passing the view function does not work.

It's interesting, but taking your example code and applying the route_name to the config
did not work for me. However, the following example, just giving the view a name sets the route url
and gives the view a name. In this fashion render_view_to_response works as advertised. Naming,
your views may not be what you want, but this configuration accomplishes the same thing as your
example code without added configuration.

@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')
江心雾 2024-12-06 03:48:48

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

创建一个视图类,其中 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()

Not the precise solution you asked for, but a solution to the problem you describe:

Create a view class, of which both foo and bar are methods. Then bar can call self.foo()

Common view_configuration, such as the template name can be applied to the class, and then you can decorate each method with just the view name.

In short, the following should meet your needs, if I understand the problem correctly.

@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()
傲鸠 2024-12-06 03:48:48

你不能做这样的事情吗:

@view_config(name="baz")
def baz_view(request):
    return HTTPFound(location=self.request.route_path('foo'))

can't you do something like that:

@view_config(name="baz")
def baz_view(request):
    return HTTPFound(location=self.request.route_path('foo'))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文