2012-05-23 57 views
28

He estado jugando con Tornado, y he escrito algún código que no parece muy bueno.Parámetros de consulta Tornado URL

Estoy escribiendo una aplicación para almacenar recetas como ejemplo. Son mis manejadores:

handlers = [ 
    (r"/recipes/", RecipeHandler), 
    (r"/recipes", RecipeSearchHandler), #so query params can be used to search 
] 

Esto me llevó a escribir este:

class RecipeHandler(RequestHandler):  
    def get(self): 
     self.render('recipes/index.html') 

class RecipeSearchHandler(RequestHandler):  
    def get(self): 
     try: 
      name = self.get_argument('name', True) 
      self.write(name) 
     # will do some searching 
     except AssertionError: 
      self.write("no params") 
      # will probably redirect to /recipes/ 

¿Hay una mejor manera de acercarse a estas URL sin un try/except? Me gustaría/recetas y/recetas/mostrar lo mismo, mientras que/recetas? Nombre = algo haría una búsqueda, e idealmente sería un manejador diferente.

Respuesta

35

Hay una mejor manera para las solicitudes GET. Hay una demostración en la fuente de tornado en github here

# url handler 
handlers = [(r"/entry/([^/]+)", EntryHandler),] 

class EntryHandler(BaseHandler): 
    def get(self, slug): 
     entry = self.db.get("SELECT * FROM entries WHERE slug = %s", slug) 
     if not entry: raise tornado.web.HTTPError(404) 
     self.render("entry.html", entry=entry) 

Cualquier "texto" que coincide con la expresión regular se pasa al método get del EntryHandler como argumento babosa. Si la URL no coincide con ningún controlador, el usuario recibirá un error 404.

Si desea proporcionar otra de reserva, podría hacer que el parámetro opcional

(r"/entry/([^/]*)", EntryHandler), 

class EntryHandler(BaseHandler): 
    def get(self, slug=None): 
     pass 

Actualización:

+1 para el enlace. Sin embargo, esto este patrón de URL se extiende para incluir más parámetros si quería buscar así ... /recetas de pollo ingrediente = & estilo indio = -? Colinjameswebb

Sí lo hace.

handlers = [ 
    (r'/(\d{4})/(\d{2})/(\d{2})/([a-zA-Z\-0-9\.:,_]+)/?', DetailHandler) 
] 

class DetailHandler(BaseHandler): 
    def get(self, year, month, day, slug): 
     pass 
+2

1 para el enlace. Sin embargo, este patrón de URL se extiende para incluir más parámetros si quisiera buscar así .../recipes? Ingredient = chicken & style = indian – colinjwebb

28

get_argument le permite proporcionar un valor por defecto:

details=self.get_argument("details", None, True) 

Si se proporciona, a continuación, se producirá una excepción si no se proporciona el argumento

8

Tornado también tiene una función get_arguments . Devuelve una lista de argumentos con el nombre dado. Si no está presente, devuelve una lista vacía ([]). Lo encontré más limpio de esta manera para desinfectar las entradas de tu servicio web en lugar de los bloques try..catch.

muestra:
Supongamos que tengo un controlador siguiente URL:

(r"/recipe",GetRecipe)

Y el controlador de solicitudes:

lista
class GetRecipe(RequestHandler): 
    def get(self): 
     recipe_id = self.get_arguments("rid") 
     if recipe_id == []: 
      # Handle me 
      self.set_status(400) 
      return self.finish("Invalid recipe id") 
     self.write({"recipe_id":self.get_argument("rid")}) 


recipe_id también sostendrá el valor, pero me pareció self.get_argument uso conveniente de esta manera.

Ahora para los resultados:

curl "http://localhost:8890/recipe" -v 

* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 8890 (#0) 
> GET /recipe HTTP/1.1 
> User-Agent: curl/7.35.0 
> Host: localhost:8890 
> Accept: */* 
> 
< HTTP/1.1 400 Bad Request 
< Content-Length: 17 
< Content-Type: text/html; charset=UTF-8 
* Server TornadoServer/1.1.1 is not blacklisted 
< Server: TornadoServer/1.1.1 
< 
* Connection #0 to host localhost left intact 
Invalid recipe id 

curl "http://localhost:8890/recipe?rid=230" -v 
* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 8890 (#0) 
> GET /recipe?rid=230 HTTP/1.1 
> User-Agent: curl/7.35.0 
> Host: localhost:8890 
> Accept: */* 
> 
< HTTP/1.1 200 OK 
< Content-Length: 20 
< Etag: "d69ecb9086a20160178ade6b13eb0b3959aa13c6" 
< Content-Type: text/javascript; charset=UTF-8 
* Server TornadoServer/1.1.1 is not blacklisted 
< Server: TornadoServer/1.1.1 
< 
* Connection #0 to host localhost left intact 
{"recipe_id": "230"} 

3

Si desea utilizar un enfoque más dinámico para el filtrado (en lugar de una dirección URL codificado) se pueden obtener todos los parámetros de URL/argumentos pasados usando self.request.arguments en el controlador de solicitud.

class ApiHandler(RequestHandler): 
    def get(self, path): 
     filters = self.request.arguments 
     for k,v in filters.items(): 
      # Do filtering etc... 

Ver http://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest.arguments

+0

Buena pista. Solo un comentario sobre cadenas Unicode. La documentación dice: Los nombres son de tipo str, mientras que los argumentos son cadenas de bytes. Tenga en cuenta que esto es diferente de RequestHandler.get_argument, que devuelve valores de argumento como cadenas de unicode. – klaas

Cuestiones relacionadas