2011-08-13 18 views
13

Mi objetivo: En la pirámide, para llamar a otro punto de vista se puede llamar, y para obtener un objeto Response vuelta sin conocer ningún detalle acerca de este punto de vista se puede llamar.otra vista en Pyramid

En mi solicitud Pirámide, decir que tengo un punto de vista "foo", que se define utilizando un decorador view_config:

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

Ahora dicen que yo quiero ruta "barra" a una vista que hace lo mismo por el momento, por lo que llama internamente foo_view y devuelve su respuesta:

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

... pero espera! Eso no funciona, ya que foo_view no devuelve un Response, su procesador de hace.

Por lo tanto, esto va a funcionar:

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

ya que se aplicará el mismo procesador que foo_view lo hicieron. Pero esto es malo, ya que ahora debo repetirme copiando el valor del procesador Y teniendo que saber el procesador de la vista a la que se llama.

Por lo tanto, voy a esperar que existe alguna funcionalidad disponible en la pirámide que permite llamar a otro punto de vista se puede llamar y obtener un objeto Response atrás sin saber o preocuparse de cómo se hizo:

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

¿Cómo sería some_function_that_renders_a_view_callable ser?

pyramid.views.render_view parece buscar una vista por su nombre; No quiero dar nombres a mis puntos de vista.

(Nota: Volviendo HTTPFound para causar el cliente para volver a dirigir a la ruta de destino es lo que estoy tratando de evitar que quiero "internamente" redirigir.). documentación

Respuesta

2

La pirámide here indica que abandonar el name palabra clave argumento de view_config hará que el fin de ser registrado por la función en sí (en lugar de una cadena):

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

Así, en su caso debe ser capaz de utilizar pyramid.view.render_view o pyramid.view.render_view_to_response referencia foo_view directamente:

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

actualización:

Sí, a la derecha, al pasar la función de vista no funciona.

Es interesante, pero tomar su código de ejemplo y aplicar el route_name a la configuración no funcionó para mí. Sin embargo, en el siguiente ejemplo, simplemente dando la vista name, establece la ruta url y le da un nombre a la vista. De esta manera, render_view_to_response funciona como se anuncia. Naming, sus puntos de vista no puede ser lo que quiera, pero esta configuración logra lo mismo que su código ejemplo, sin necesidad de configuración adicional.

@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

Esto se traduce en "No se puede convertir vista ValueError valor de retorno '' en un objeto de respuesta". ¿Hay algo más que deba hacer en la vista de destino para que esto funcione? – kes

1

que no se puede hacer algo así:

@view_config (name = "Baz") baz_view def (petición): retorno HTTPFound (location = self.request.route_path ('foo '))

+1

Sí y no: el redireccionamiento de HTTP es el doble del viaje de ida y vuelta, y podría ser confuso para el usuario si nota que la página devuelta está en otra URL diferente a la solicitada. Lo último se vuelve más preocupante cuando la URL original de la que estamos hablando es la página de inicio '/'. – Jerry

+0

Esa es una gran manera de hacer un redireccionamiento a una vista sin utilizar una URL y, IMO, es preferible a llamar internamente a otras vistas. – Javier

3

Yo estaba luchando con esto también. Tengo una solución usando el render_to_response method, aunque estoy seguro de que hay una manera "más correcta" de hacerlo. Hasta que alguien publica que, sin embargo, aquí es cómo he manejado esto:

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) 

(Pirámide 1.3)

Esto requiere un procesador para ser utilizado, pero declarando que renderizador de valores de retorno de la vista original, puede recuperarlo en otra vista sin saber qué es. Estoy sospechando que la necesidad de hacer esto no es fácil de encontrar porque hay otros mejores métodos para llevar a cabo las tareas resueltas por esta solución.

Otro inconveniente es que depende de la importación directa de la vista invocable. Sería bueno si se pudiera buscar directamente por ruta.

1

No es la solución precisa que pidieron, pero una solución al problema que usted describe:

Crear una clase de vista, de los cuales tanto foo y bar son métodos. A continuación, la barra puede llamar a self.foo()

La configuración view_común, como el nombre de la plantilla, se puede aplicar a la clase y, a continuación, puede decorar cada método con solo el nombre de la vista.

En resumen, lo siguiente debe satisfacer sus necesidades, si entiendo el problema correctamente.

@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() 
+0

concedida, esta puede no haber sido una opción cuando se planteó la pregunta. No estoy seguro de cuándo salió la pirámide 1.3. – mac01021

+0

* Mi objetivo: en Pyramid, llamar a otro view-collable y recuperar un objeto Response sin conocer ningún detalle sobre ese view-invocable. * Ciertamente tener que colocar * otro * view-invocable en una clase específica está en oposición directa no * saber ningún detalle sobre esa vista-invocable. * –

+0

Bastante seguro de que esto no funciona. Esto es lo que sucedió cuando lo probé: ValueError: no se pudo convertir el valor devuelto del método de vista invocable foo_view de la clase example.views.ExampleViews en un objeto de respuesta. El valor devuelto fue {'whereami': 'foo!'}. Es posible que haya olvidado definir un procesador en la configuración de vista. – jmercouris

8

Yep. Hay algunas preocupaciones

  • no devuelve una respuesta
  • predicados/renderer
  • permisos
  • propiedades petición asociada a la solicitud de edad

Es por eso que no debe llamar a la vista de la vista como función, a menos que sepa lo que está haciendo

Los creadores de pirámides hicieron una herramienta increíble para el lado del servidor redirigir - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html

2

Puede invocar una vista con el uso de request.invoke_subrequest: Ninguno:

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.

Cuestiones relacionadas