Question Appeler une autre vue dans Pyramid


Mon objectif: dans Pyramid, appeler un autre appel-vue et obtenir un Response object back sans connaître les détails de cette vue-appelable.

Dans mon application Pyramid, disons que j'ai une vue "foo" qui est définie en utilisant un décorateur view_config:

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

Maintenant, disons que je veux acheminer "bar" vers une vue qui fait la même chose pour le moment, donc elle appelle en interne foo_view et renvoie sa réponse:

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

...mais attendez! Cela ne marche pas, puisque foo_view ne retourne pas un Response, son moteur de rendu Est-ce que.

Donc ça va marcher:

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

comme il va appliquer le même moteur de rendu que foo_view fait. Mais c'est mauvais, car je dois maintenant me répéter en copiant la valeur du rendu ET en ayant à connaître le rendu de la vue appelée.

Donc, je vais espérer qu'il y a une fonction disponible dans Pyramid qui permet d'appeler une autre vue et d'obtenir un Response objet retour sans savoir ou se soucier comment il a été rendu:

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

Quel serait some_function_that_renders_a_view_callable être?

pyramid.views.render_view apparaît pour rechercher une vue par nom; Je ne veux pas donner de nom à mes opinions.

(Remarque: je souhaite éviter de renvoyer HTTPFound pour que le client soit redirigé vers la route cible. Je souhaite une redirection «interne»).


13
2017-08-13 02:47


origine


Réponses:


Oui. Il y a des soucis

  • ne renvoie pas de réponse
  • prédicats / moteur de rendu
  • autorisations
  • demande les propriétés associées à l'ancienne demande

C'est pourquoi vous ne devriez pas appeler view from view comme fonction, à moins de savoir ce que vous faites

Les créateurs de pyramides ont fait un outil génial pour la redirection côté serveur - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html


8
2018-06-15 12:55



Je me débattais aussi avec ça. J'ai une solution en utilisant le Méthode render_to_response, bien que je sois sûr qu'il existe une manière plus "correcte" de le faire. Jusqu'à ce que quelqu'un l'affiche, voici comment j'ai géré ceci:

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)

(Pyramide 1.3)

Cela nécessite l'utilisation d'un moteur de rendu, mais en déclarant ce moteur de rendu dans les valeurs de la vue d'origine, vous pouvez le récupérer dans une autre vue sans savoir de quoi il s'agit. Je soupçonne que la nécessité de le faire n'est pas facilement identifiable car il existe d'autres méthodes plus efficaces pour accomplir les tâches résolues par cette solution.

Un autre inconvénient est qu'il repose sur l'importation directe de la vue appelable. Ce serait bien si on pouvait le rechercher directement par route.


3
2017-08-19 14:20



La documentation de la pyramide ici indique que quitter le name mot clé argument hors view_config provoquera l'enregistrement de la vue par la fonction elle-même (plutôt qu'une chaîne):

Un tel enregistrement implique que le nom de la vue sera * my_view *

Donc, dans votre cas, vous devriez pouvoir utiliser pyramid.view.render_view ou pyramid.view.render_view_to_response référencement foo_view directement:

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

Mettre à jour:

Oui, votre droit, Passer la fonction d'affichage ne fonctionne pas.

C'est intéressant, mais en prenant votre exemple de code et en appliquant le code route_name à la config N'a pas travaillé pour moi. Cependant, l'exemple suivant, en donnant simplement à la vue une namedéfinit l'URL de la route et donne un nom à la vue. Dans cette mode render_view_to_response fonctionne comme annoncé. Appellation, vos vues peuvent ne pas être ce que vous voulez, mais cette configuration accomplit la même chose que votre exemple de code sans configuration supplémentaire.

@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')

2
2017-08-13 07:40



Vous pouvez invoquer une vue avec 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()`

Quand /view_one est visted dans un navigateur, le texte imprimé dans le   Le volet du navigateur sera "Ceci vient de view_two". le view_one vue   utilisé le pyramid.request.Request.invoke_subrequest() API pour obtenir un   réponse d'une autre vue (view_two) dans la même application   quand il a exécuté. Il l'a fait en construisant une nouvelle demande qui avait un   L'URL qu'il savait correspondrait à la view_two voir l'inscription, et   passé cette nouvelle demande à    pyramid.request.Request.invoke_subrequest(). le view_two vue   callable a été invoqué et une réponse a été renvoyée. le view_one vue   callable puis simplement retourné la réponse obtenue de la    view_two voir appelable.


2
2018-05-29 13:29



tu ne peux pas faire quelque chose comme ça:

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


1
2018-01-16 19:35



Pas la solution précise que vous avez demandée, mais une solution au problème que vous décrivez:

Créez une classe de vue, dont foo et bar sont des méthodes. Alors la barre peut appeler self.foo ()

La configuration de vue commune, telle que le nom du modèle, peut être appliquée à la classe. Vous pouvez ensuite décorer chaque méthode avec uniquement le nom de la vue.

En bref, les éléments suivants devraient répondre à vos besoins, si je comprends bien le problème.

@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
2018-02-07 19:39