Set url for Tornado handlers
To set url for tornado handlers we can pass list of tuples (url regex, handler)
into application initialisation:
application = tornado.web.Application([
(r"/", MainHandler),
(r"/some/path/page/(?P<pk>[0-9]+)$", PageHandler),
])
But it is more convenient to use wrapper tornado.web.url
, that allows to assign meaningful names for paths (similar to django url).
Nevertheless, in a couple of production projects that i had to work with, this wrapper wasn’t used. Also in some tornado examples from documentation (one, two, three) simple tuples are used, that can be confusing. So i think that it is worth to mention the advantages, that gives url wrapper.
So, what disadvantages we’ll face in case of tuples, i.e. without using a url.
Without url()
To represent needed path in code or in template, we have to manually enter the string.
Example.
**app.py**:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("home.html", title="My title", pages=[1, 2, 3])
class PageHandler(tornado.web.RequestHandler):
def get(self, page_n):
email_text = "Please visit this page: '/some/path/page/{page_n}/'".format(
page_n=1)
send_email('some@person.com', email_text)
self.render("page.html", title="Page", page_n=page_n)
application = tornado.web.Application([
(r"/", MainHandler),
(r"/some/path/page/(?P<page_n>[0-9]+)/$", PageHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
home.htm:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div>View pages:</div>
<ul>
{% for page_n in pages %}
<li><a href="/some/path/page/{{ page_n }}/">{{ page_n }}</a></li>
{% end %}
</ul>
</body>
</html>
page.html:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div>You are viewing page #{{ page_n }}</div>
<div>Back to <a href="/">Home<a></div>
</body>
</html>
As we can see, even in this simple code we repeat path /some/path/page/
three times. What if we’ll need to change this string a little? We’ll have to make an autocorrect, that is uncomfortably and can lead to errors. Furthermore, some paths can be cumbersome and decrease code readability.
With url()
Same example, but with url
:
app.py:
import tornado.ioloop
import tornado.web
from tornado.web import url
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("home.html", title="My title", pages=[1, 2, 3])
class PageHandler(tornado.web.RequestHandler):
def get(self, page_n):
email_text = "Please visit this page: '{url}'".format(
url=self.reverse_url('page', 1))
send_email('some@person.com', email_text)
self.render("page.html", title="Page", page_n=page_n)
application = tornado.web.Application([
url(r"/", MainHandler, name="home"),
url(r"/some/path/page/(?P<page_n>[0-9]+)/$", PageHandler, name="page"),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
home.html:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div>View pages:</div>
<ul>
{% for page_n in pages %}
<li><a href="{{reverse_url('page', page_n)}}">{{ page_n }}</a></li>
{% end %}
</ul>
</body>
</html>
page.html:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div>You are viewing page #{{ page_n }}</div>
<div>Back to <a href="{{reverse_url('home')}}">Home<a></div>
</body>
</html>
Paths now have meaningful names that are used in url representation by method reverse_url
. If it is needed to change some path, we’ll do it in one single place. Much more convenient!