Задание url для обработчиков Tornado
В tornado, для привязки обработчиков к url’ам, можно передать список из кортежей (url regex, handler)
при инициализации приложения:
application = tornado.web.Application([
(r"/", MainHandler),
(r"/some/path/page/(?P<pk>[0-9]+)$", PageHandler),
])
Но не секрет, что гораздо удобнее использовать обертку tornado.web.url
, которая позволяет присваивать имена для путей (похожа на django’вский url).
Однако, в паре рабочих проектах, с которыми приходилось работать, эта обертка не использовалась. А так же в некоторых примерах из tornado документации (раз, два, три) тоже используются обычные кортежи, без url, что может сбить с толку. Поэтому считаю полезным описать те преимущества, которые дает эта обертка.
Итак, какие неудобства мы испытываем при работе без использования url.
Без url()
Чтобы в коде или в шаблоне воспроизвести нужный путь, приходится вручную вводить строку.
Пример
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>
Видим, что даже в этом простом коде пришлось трижды повторять путь /some/path/page/
. А если нам понадобится чуть-чуть изменить эту строку? Придется делать автозамену, что неудобно и чревато ошибками. К тому же, некоторые пути могут быть громоздкими, что ухудшает читабельность кода.
Используя url()
Этот же пример, но с оберткой 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>
Путям присвоены значащие имена, которые используются для воспроизведения url’a с помощью метода reverse_url
. Если нам нужно будет подправить какой-либо путь, то мы сделаем это лишь в одном месте. Гораздо удобнее!