2012-05-23 23 views
28

Ho giocato con Tornado e ho scritto del codice che non sembra molto bello.Parametri query URL Tornado

Sto scrivendo un'app per memorizzare le ricette come esempio. Questi sono i miei gestori:

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

Questo mi ha portato a scrivere questo:

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/ 

C'è un modo migliore per avvicinarsi a questi URL senza un try/tranne? Mi piacerebbe/ricette e/ricette/per mostrare la stessa cosa, mentre/ricette? Name = qualcosa farebbe una ricerca, e idealmente essere un gestore diverso.

risposta

35

Esiste un modo migliore per le richieste GET. C'è una demo nella fonte tornado su 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) 

Qualsiasi "testo" che corrisponde all'espressione regolare sarà passato al metodo get della EntryHandler come argomento lumaca. Se l'url non corrisponde a nessun gestore, l'utente riceverà un errore 404.

Se si voleva fornire un altro ripiego, si potrebbe creare il parametro opzionale

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

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

Aggiornamento:

+1 per il collegamento. Tuttavia non questo pattern URL estende per includere più parametri se volevo cercare in questo modo ... /Ricette ingrediente = pollo & style = indiano -? Colinjameswebb

Sì lo fa.

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 per il collegamento. Tuttavia questo pattern URL si estende per includere più parametri se volessi cercare in questo modo .../recipes? Ingredient = chicken & style = indian – colinjwebb

28

get_argument consente di fornire un valore predefinito:

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

Se è previsto, quindi si verificherà un'eccezione se l'argomento non viene fornito

8

Tornado ha anche una funzione di get_arguments . Restituisce un elenco di argomenti con il nome specificato. Se non presente, restituisce una lista vuota ([]). L'ho trovato più pulito in questo modo per disinfettare gli input del servizio Web anziché i blocchi try..catch.

Esempio:
Si supponga Ho un seguente gestore URL:

(r"/recipe",GetRecipe)

E il gestore di richieste:

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 lista terrà anche il valore, ma ho trovato self.get_argument utilizzo conveniente in questo modo.

Ora per i risultati:

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

Se si desidera utilizzare un approccio più dinamico per il filtraggio (al posto di un URL hard coded) è possibile ottenere tutte le URL parametri/argomenti passati utilizzando self.request.arguments nel gestore richieste.

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

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

+0

Buon suggerimento. Solo un'osservazione riguardante le stringhe Unicode. La documentazione dice: i nomi sono di tipo str, mentre gli argomenti sono stringhe di byte. Si noti che questo è diverso da RequestHandler.get_argument, che restituisce valori di argomento come stringhe Unicode. – klaas