Вызов другого вида в пирамиде - PullRequest
14 голосов
/ 13 августа 2011

Моя цель: в Pyramid вызвать другой вызываемый вид и вернуть объект Response, не зная никаких подробностей об этом вызываемом представлении.

В моем приложении Pyramid, скажем, у меня есть представление "foo", которое определяется с помощью декоратора view_config:

@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 для перенаправления клиента на целевой маршрут - это то, чего я пытаюсь избежать. Я хочу «внутренне» перенаправить).

Ответы [ 6 ]

8 голосов
/ 15 июня 2013

Да.Есть некоторые опасения, что

  • не возвращает ответ
  • предикаты / средства визуализации
  • разрешения
  • свойства запроса, связанные со старым запросом

Вот почему вы не должны вызывать представление из вида как функцию, если только вы не знаете, что делаете

Создатели пирамид сделали потрясающий инструмент для перенаправления на стороне сервера - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html

3 голосов
/ 29 мая 2015

Вы можете вызвать представление с помощью 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 вид использовал API pyramid.request.Request.invoke_subrequest() для получения ответ из другого представления (view_two) в том же приложении когда это выполнено. Это было сделано путем создания нового запроса, который имел URL, который он знал, будет соответствовать регистрации view_two, и передал этот новый запрос pyramid.request.Request.invoke_subrequest(). view_two вид вызываемый был вызван, и он возвратил ответ. view_one вид вызываемый затем просто вернул ответ, полученный от view_two просмотр вызываемого.

3 голосов
/ 19 августа 2012

Я тоже боролся с этим.У меня есть решение, использующее метод 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)

Для этого требуется использовать средство визуализации, но объявив его в исходном представлениивозвращая значения, вы можете получить его в другом представлении, не зная, что это такое.Я подозреваю, что необходимость сделать это не легко найти, потому что есть другие, лучшие методы для решения задач, решаемых этим решением.

Еще один недостаток заключается в том, что он полагается на прямой импорт вызываемого представления.Было бы неплохо, если бы его можно было искать непосредственно по маршруту.

2 голосов
/ 13 августа 2011

Документация Pyramid здесь указывает, что оставление аргумента name ключевого слова из view_config приведет к тому, что представление будет зарегистрировано самой функцией (а не строкой):

Такая регистрация ... подразумевает, что имя представления будет * my_view *

Итак, в вашем случае вы сможете использовать pyramid.view.render_view или pyramid.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')
1 голос
/ 07 февраля 2013

Не точное решение, которое вы просили, а решение описанной вами проблемы:

Создайте класс представления, для которого foo и 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()
1 голос
/ 16 января 2012

ты не можешь сделать что-то подобное:

@ view_config (имя = "Баз") def baz_view (запрос): вернуть HTTPFound (location = self.request.route_path ('foo'))

...