2011-01-08 8 views
20
# /test{.format} no longer seems to work... 
config.add_route('test', '/test.{ext}', view='ms.views.test') 

views.py:¿Existe alguna forma mejor de cambiar entre HTML y JSON en Pyramid?

from pyramid.response import Response 
from pyramid.renderers import render 

import json 

def test(request): 
    extension = request.matchdict['ext'] 
    variables = {'name' : 'blah', 'asd' : 'sdf'} 

    if extension == 'html': 
     output = render('mypackage:templates/blah.pt', variables, request=request) 

    if extension == 'json': 
     output = json.dumps(variables) 

    return Response(output) 

¿Hay una manera más fácil de hacer esto? Con los pilones, que era un simple:

def test(self, format='html'): 
    c.variables = {'a' : '1', 'b' : '2'} 

    if format == 'json': 
     return json.dumps(c.variables) 

    return render('/templates/blah.html') 

sospecho que estoy acercarse a mal ...?

+0

¿Cuál es su queja? ¿Te estás quejando de que la pirámide tiene API diferentes de las torres? Si no te gustan las API piramidales, ¿por qué no vuelves a Pylons? –

+0

Does not Pyramid usa middleware? ¿Por qué no puedes renderizar JSON en función de lo que solicita el usuario? Hacer dentro de la vista directamente, está en mi libro, una solución defectuosa. Si es posible, aproveche el middleware. – Anders

Respuesta

6

¿Esto es lo que estás buscando? Pylons y Pyramid tienen diferentes API. Entonces ellos serán diferentes. Puedes hacerlos un poco más similares, pero no puedes hacerlos idénticos.

def test(request): 
    extension = request.matchdict['ext'] 
    variables = {'name' : 'blah', 'asd' : 'sdf'} 

    if extension == 'json': 
     return Response(json.dumps(variables)) 

    return Response(render('mypackage:templates/blah.pt', variables, request=request)) 
+0

+1 esa es la traducción uno a uno al ejemplo del PO. –

+0

@Tom Willis: que no puede ser la verdadera pregunta. ¿Puede? –

51

Creo que la mejor manera es agregar la misma vista dos veces con diferentes representadores. Supongamos que tenemos el siguiente punto de vista:

def my_view(request): 
    return {"message": "Hello, world!"} 

Ahora en nuestra configuración que se puede añadir el mismo punto de vista doble:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test', '/test', my_view, renderer="json", xhr=True) 

Lo que tenemos ahora:

  1. Ver my_view rendirá plantilla "templates/my_template.mako" con dict devuelto proporcionado como contexto si direccionaremos nuestro navegador a url /test.
  2. Si haremos una solicitud XHR con my_view se volverá a llamar, pero ahora se devuelve el dict se codificará como JSON y se transmitirá a la persona que llama (read docs para verificar si la solicitud se realizó a través de XHR).

La misma idea se puede utilizar para definir diferentes rutas, pero con la misma vista unido a ellos:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test_json', '/test.json', my_view, renderer="json") 

Ahora /test activará prestación plantilla, pero /test.json volverá cadena acaba de JSON codificado.

Puede ir más allá y hacer el envío al procesador de la derecha a través de accept argumento de add_router método:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test', '/test', my_view, renderer="json", accept="application/json") 

Si la solicitud viene con cabecera Accept conjunto de application/json valor JSON será devuelto, plantilla de lo contrario se consiguió prestados.

Tenga en cuenta que esto solo funcionará si tiene un conjunto predefinido de formatos de datos en los que desea codificar las respuestas de sus vistas, pero es el caso habitual. En caso de que necesite un despacho dinámico, puede decorar sus vistas con el argumento decorate del add_route, que elegirá el renderizador adecuado con sus reglas.

+3

+1 Creo que esto refleja mejor la "forma piramidal" de hacer las cosas. Es flexible, desacopla las vistas de los renderizadores haciendo que las vistas sean más sencillas para la prueba unitaria porque en lugar de analizar un documento html puede buscar valores en un diccionario. –

+0

Esto parece una buena manera de hacerlo. ¿Cómo podría aplicar este método a mis métodos de manejo? Encontré, en la documentación, que puedes decorar funciones con 'view_config' que te permitirá configurar el renderizador pero no pude ver un equivalente para el Despacho de URL. – dave

+0

¿No funciona 'add_handler' de esta manera?Nunca he trabajado con controladores, pero la documentación indica que "Cualquier argumento adicional de palabra clave se transfiere a add_route". – andreypopp

2

PyramidURL Dispatch es un mecanismo muy potente y flexible. En primer lugar, escribiremos el patrón de URL correcto. En route pattern syntax podemos usar regular expressions para los marcadores de reemplazo.

'/test{ext:\\..*}' 

Aquí podemos ver que ruta URL debe contener. (punto) y luego cualquier símbolo. Todos los símbolos incluidos (período) estará bajo la clave ext en request.matchdict.

Por supuesto, podemos complicar la expresión regular con el fin de especificar qué extensiones no pueden ser:

'/test{ext:\\.(html|json)}' 

Luego añadir la ruta con nuestro patrón:

config.add_route('test', 
       pattern='/test{ext:\\.(html|json)}') 

desea agregar , que podemos especificar el conjunto de extensiones usando custom predicates.

Para especificar la extensión predeterminada podemos usar pregenerator simple.

def default_extension(ext): 
    def pregenerator(request, elements, kw): 
     if 'ext' not in kw: 
      kw['ext'] = ext 

     return elements, kw 

    return pregenerator 

config.add_route('test', 
       pattern='/test{ext:\\.(html|json)}', 
       pregenerator=default_extension('.html')) 

request.route_path('test') 
# '/test.html' 
request.route_path('test', ext='.json') 
# '/test.json' 

Después de que vamos a Traversal que nos ayude a cambiar entre html y JSON de salida:

config.add_route('test', 
       '/test{ext:\\.(html|json)}', 
       pregenerator=default_extension('.html'), 
       traverse='{ext}') 

Con el argumento traverse en add_route forzamos nuestra aplicación sea hybrid. Y debemos entender que la fábrica que proporcionará contexto para nuestras vistas no debe contener las claves que coinciden con nuestras extensiones. La fábrica de raíz predeterminada no funciona.

views.py:

from pyramid.view import view_config, view_defaults 


@view_defaults(route_name='test') 
class Test(object): 
    def __init__(self, request): 
     self.request = request 
     self.variables = { 
      'name': 'blah', 
      'asd': 'sdf' 
     } 

    @view_config(name='.html', renderer='mypackage:templates/blah.pt') 
    def html(request): 
     return { 
      'request': request, 
      'variables': self.variables 
     } 

    @view_config(name='.json', renderer='json') 
    def json(request): 
     return { 
      'request': request, 
      'variables': self.variables 
     } 

Aquí hemos creado class Test y especificar nombre de la ruta por ello. Y luego hemos separado los métodos por los nombres de nuestras extensiones.

+0

Me gusta el uso de transversal para diferenciar el comportamiento en las diferentes extensiones. La configuración de vista puede ser dramáticamente más simple. Podría ser una función única que acepte una solicitud decorada con 2 líneas '@ view_config', ambas con' route_name', con diferentes 'name's y' renderer's. Hace el ejemplo significativamente menos complejo (solo 7 líneas de código). – Elmer

0

Trate de esta manera:

def test(self, format='html'): 
    c.variables = {'a' : '1', 'b' : '2'} 

    if format == 'json': 
     return Response(json = c.variables) 

    return render_to_response('/templates/blah.html') 

Esta es la más similar a su ejemplo, torres de alta tensión. También muestra una forma más amigable de presentar una plantilla o algún JSON a una respuesta.

Cuestiones relacionadas