Tornado 4.3
於2015年11月6日發佈,該版本正式支持Python3.5
的async
/await
關鍵字,而且用舊版本CPython編譯Tornado一樣可使用這兩個關鍵字,這無疑是一種進步。其次,這是最後一個支持Python2.6
和Python3.2
的版本了,在後續的版本了會移除對它們的兼容。如今網絡上尚未Tornado4.3
的中文文檔,因此爲了讓更多的朋友能接觸並學習到它,我開始了這個翻譯項目,但願感興趣的小夥伴能夠一塊兒參與翻譯,項目地址是tornado-zh on Github,翻譯好的文檔在Read the Docs上直接能夠看到。歡迎Issues or PR。javascript
Tornado 包含一個簡單,快速並靈活的模板語言. 本節介紹了語言以及相關的問題,好比國際化.css
Tornado 也可使用其餘的Python模板語言, 雖然沒有準備把這些系統整合到 RequestHandler.render
裏面. 而是簡單的將模板轉成字符串並傳遞給 RequestHandler.write
html
默認狀況下, Tornado會在和當前.py
文件相同的目錄查找關聯的模板文件. 若是想把你的模板文件放在不一樣的目錄中, 可使用template_path
Application setting (或複寫 RequestHandler.get_template_path
若是你不一樣的處理函數有不一樣的模板路徑).java
爲了從非文件系統位置加載模板, 實例化子類 tornado.template.BaseLoader
併爲其在應用設置(application setting)中配置template_loader
.python
默認狀況下編譯出來的模板會被緩存; 爲了關掉這個緩存也爲了使(對目標的)修改在從新加載後老是可見, 使用應用設置(application settings)中的compiled_template_cache=False
或debug=True
.git
一個Tornado模板僅僅是用一些標記把Python控制序列和表達式嵌入HTML(或者任意其餘文本格式)的文件中:github
<html> <head> <title>{{ title }}</title> </head> <body> <ul> {% for item in items %} <li>{{ escape(item) }}</li> {% end %} </ul> </body> </html>
若是你把這個目標保存爲"template.html"而且把它放在你Python文件的相同目錄下, 你可使用下面的代碼渲染它:web
class MainHandler(tornado.web.RequestHandler): def get(self): items = ["Item 1", "Item 2", "Item 3"] self.render("template.html", title="My title", items=items)
Tornado模板支持控制語句(control statements)和表達式(expressions).控制語句被包在{%
和%}
中間, 例如,{% if len(items) > 2 %}
. 表達式被包在{{
和}}
之間, e.g.,{{ items[0] }}
.express
控制語句或多或少都和Python語句相似. 咱們支持if
,for
,while
, 和try
, 這些都必須使用{% end %}
來標識結束. 咱們也支持 模板繼承(template inheritance) 使用extends
和block
標籤聲明, 這些內容的詳細信息均可以在 tornado.template
中看到.json
表達式能夠是任意的Python表達式, 包括函數調用. 模板代碼會在包含如下對象和函數的命名空間中執行 (注意這個列表適用於使用 RequestHandler.render
和RequestHandler.render_string
渲染模板的狀況. 若是你直接在RequestHandler
以外使用tornado.template
模塊, 下面這些不少都不存在).
escape
: tornado.escape.xhtml_escape
的別名
xhtml_escape
: tornado.escape.xhtml_escape
的別名
url_escape
: tornado.escape.url_escape
的別名
json_encode
: tornado.escape.json_encode
的別名
squeeze
: tornado.escape.squeeze
的別名
linkify
: tornado.escape.linkify
的別名
datetime
: Python datetime
模塊
handler
: 當前的 RequestHandler
對象
request
: handler.request
的別名
current_user
: handler.current_user
的別名
locale
: handler.locale
的別名
_
: handler.locale.translate
的別名
static_url
: handler.static_url
的別名
xsrf_form_html
: handler.xsrf_form_html
的別名
reverse_url
: Application.reverse_url
的別名
全部從ui_methods
和ui_modules
`Application
`設置的條目
任何傳遞給 RequestHandler.render
或RequestHandler.render_string
的關鍵字參數
當你正在構建一個真正的應用, 你可能想要使用Tornado模板的全部特性,尤爲是目標繼承. 閱讀全部關於這些特性的介紹在 tornado.template
部分 (一些特性, 包括UIModules
是在 tornado.web
模塊中實現的)
在引擎下, Tornado模板被直接轉換爲Python. 包含在你模板中的表達式會逐字的複製到一個表明你模板的Python函數中. 咱們不會試圖阻止模板語言中的任何東西; 咱們明確的創造一個高度靈活的模板系統, 而不是有嚴格限制的模板系統. 所以, 若是你在模板表達式中隨意填充(代碼), 當你執行它的時候你也會獲得各類隨機錯誤.
全部模板輸出默認都會使用 tornado.escape.xhtml_escape
函數轉義.這個行爲能夠經過傳遞autoescape=None
給 Application
或者tornado.template.Loader
構造器來全局改變, 對於一個模板文件可使用{% autoescape None %}
指令, 對於一個單一表達式可使用{% raw ...%}
來代替{{ ... }}
. 此外, 在每一個地方一個可選的轉義函數名能夠被用來代替None
.
注意, 雖然Tornado的自動轉義在預防XSS漏洞上是有幫助的, 可是它並不能勝任全部的狀況. 在某一位置出現的表達式, 例如Javascript 或 CSS, 可能須要另外的轉義. 此外, 要麼是必須注意老是在可能包含不可信內容的HTML中使用雙引號和 xhtml_escape
, 要麼必須在屬性中使用單獨的轉義函數(參見 e.g. http://wonko.com/post/html-escaping)
當前用戶的區域設置(不管他們是否登陸)老是能夠經過在請求處理程序中使用self.locale
或者在模板中使用locale
進行訪問. 區域的名字(e.g.,en_US
) 能夠經過locale.name
得到, 你能夠翻譯字符串經過 Locale.translate
方法. 模板也有一個叫作_()
全局函數用來進行字符串翻譯. 翻譯函數有兩種形式:
_("Translate this string")
是直接根據當前的區域設置進行翻譯, 還有:
_("A person liked this", "%(num)d people liked this", len(people)) % {"num": len(people)}
是能夠根據第三個參數的值來翻譯字符串單複數的. 在上面的例子中,若是len(people)
是1
, 那麼第一句翻譯將被返回, 其餘狀況第二句的翻譯將會返回.
翻譯最通用的模式四使用Python命名佔位符變量(上面例子中的%(num)d
) 由於佔位符能夠在翻譯時變化.
這是一個正確的國際化模板:
<html> <head> <title>FriendFeed - {{ _("Sign in") }}</title> </head> <body> <form action="{{ request.path }}" method="post"> <div>{{ _("Username") }} <input type="text" name="username"/></div> <div>{{ _("Password") }} <input type="password" name="password"/></div> <div><input type="submit" value="{{ _("Sign in") }}"/></div> {% module xsrf_form_html() %} </form> </body> </html>
默認狀況下, 咱們經過用戶的瀏覽器發送的Accept-Language
頭來發現用戶的區域設置. 若是咱們沒有發現恰當的Accept-Language
值, 咱們會使用en_US
. 若是你讓用戶進行本身偏心的區域設置, 你能夠經過複寫 RequestHandler.get_user_locale
來覆蓋默認選擇的區域:
class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): user_id = self.get_secure_cookie("user") if not user_id: return None return self.backend.get_user_by_id(user_id) def get_user_locale(self): if "locale" not in self.current_user.prefs: # Use the Accept-Language header return None return self.current_user.prefs["locale"]
若是get_user_locale
返回None
,那咱們(繼續)依靠Accept-Language
頭(進行判斷).
tornado.locale
模塊支持兩種形式加載翻譯: 一種是用gettext
和相關的工具的.mo
格式, 還有一種是簡單的.csv
格式.應用程序在啓動時一般會調用一次 tornado.locale.load_translations
或者 tornado.locale.load_gettext_translations
其中之一; 查看這些方法來獲取更多有關支持格式的詳細信息..
你可使用 tornado.locale.get_supported_locales()
獲得你的應用所支持的區域(設置)列表. 用戶的區域是從被支持的區域中選擇距離最近的匹配獲得的.例如, 若是用戶的區域是es_GT
, 同時es
區域是被支持的, 請求中的self.locale
將會設置爲es
. 若是找不到距離最近的匹配項, 咱們將會使用en_US
.
Tornado支持UI modules使它易於支持標準, 在你的應用程序中複用UI組件. UI模塊像是特殊的函數調用來渲染你的頁面上的組件而且它們能夠包裝本身的CSS和JavaScript.
例如, 若是你實現一個博客, 而且你想要有博客入口出如今首頁和每篇博客頁, 你能夠實現一個Entry
模塊來在這些頁面上渲染它們. 首先,爲你的UI模塊新建一個Python模塊, e.g.,uimodules.py
:
class Entry(tornado.web.UIModule): def render(self, entry, show_comments=False): return self.render_string( "module-entry.html", entry=entry, show_comments=show_comments)
在你的應用設置中, 使用ui_modules
配置, 告訴Tornado使用uimodules.py
:
from . import uimodules class HomeHandler(tornado.web.RequestHandler): def get(self): entries = self.db.query("SELECT * FROM entries ORDER BY date DESC") self.render("home.html", entries=entries) class EntryHandler(tornado.web.RequestHandler): def get(self, entry_id): entry = self.db.get("SELECT * FROM entries WHERE id = %s", entry_id) if not entry: raise tornado.web.HTTPError(404) self.render("entry.html", entry=entry) settings = { "ui_modules": uimodules, } application = tornado.web.Application([ (r"/", HomeHandler), (r"/entry/([0-9]+)", EntryHandler), ], **settings)
在一個模板中, 你可使用{% module %}
語法調用一個模塊. 例如,你能夠調用Entry
模塊從home.html
:
{% for entry in entries %} {% module Entry(entry) %} {% end %}
和entry.html
:
{% module Entry(entry, show_comments=True) %}
模塊能夠包含自定義的CSS和JavaScript函數, 經過複寫embedded_css
,embedded_javascript
,javascript_files
, 或css_files
方法:
class Entry(tornado.web.UIModule): def embedded_css(self): return ".entry { margin-bottom: 1em; }" def render(self, entry, show_comments=False): return self.render_string( "module-entry.html", show_comments=show_comments)
模塊CSS和JavaScript將被加載(或包含)一次, 不管模塊在一個頁面上被使用多少次. CSS老是包含在頁面的<head>
標籤中, JavaScript 老是被包含在頁面最底部的</body>
標籤以前.
當不須要額外的Python代碼時, 一個模板文件自己能夠做爲一個模塊. 例如,先前的例子能夠重寫到下面的module-entry.html
:
{{ set_resources(embedded_css=".entry { margin-bottom: 1em; }") }} <!-- more template html... -->
這個被修改過的模塊模塊能夠被引用:
{% module Template("module-entry.html", show_comments=True) %}
set_resources
函數只能在模板中經過{% module Template(...) %}
纔可用. 不像{% include ... %}
指令, 模板模塊有一個明確的命名空間它們的包含模板-它們只能看到全局模板命名空間和它們本身的關鍵字參數.