導航
用戶指南
模板與UI
Tornado包含一種簡單,快速,靈活的模板語言。 本節介紹該語言以及國際化等相關問題。
Tornado可以任意使用其他的Python模板語言,哪怕它們並沒有被集成到RequestHandler.render
中。 只需將模板渲染爲字符串並將其傳遞給RequestHandler.write
即可。
配置模板
默認情況下,Tornado在與引用它們的.py文件的目錄中查找模板文件。要將模板文件放在不同的目錄中,請使用template_path
應用程序設置(如果不同的處理程序具有不同的模板路徑,則修改RequestHandler.get_template_path
)即可。
要從非文件系統位置加載模板,請子類化tornado.template.BaseLoader
,並傳遞一個使用template_loader
應用程序設置的實例。
默認情況下,編譯的模板會被緩存;要關閉此緩存和重新加載模板,以便始終可以看到對底層文件的更改,請使用應用程序設置compiled_template_cache = False
或debug = True
。
模板語法
Tornado模板只是使用Python控制語句和內嵌表達式標記的HTML(或任何其他基於文本的格式)。
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<ul>
{% for item in items %}
<li>{{ escape(item) }}</li>
{% end %}
</ul>
</body>
</html>
如果你將這個模板保存爲“template.html”並將它放入python文件所在的目錄中,你可以使用下面的代碼渲染這個模板:
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模板支持控制語句和表達式。 控制語句由{%
和%}
包圍,例如{% if len(items) > 2 %}
。 表達式由{{
和}}
包圍,例如{{items [0]}}
。
控制語句或多或少地映射到Python語句。我們支持if
,for
,while
和try
,所有這些都以{% end% }
結束。我們還使用extends
和block
語句支持模板繼承(template inheritance),這些語句在tornado.template
的文檔中有詳細描述。
表達式可以是包括函數調用的任何Python表達式。模板代碼在包含以下對象和函數的命名空間中執行(請注意,此列表僅適用於使用RequestHandler.render
和render_string
渲染的模板。如果你直接在RequestHandler
之外使用tornado.template
模塊,下面的許多項都將無法使用)。
escape
: tornado.escape.xhtml_escapexhtml_escape
: tornado.escape.xhtml_escapeurl_escape
: tornado.escape.url_escapejson_encode
: tornado.escape.json_encodesqueeze
: tornado.escape.squeezelinkify
: tornado.escape.linkifydatetime
: the Python datetime modulehandler
: the current RequestHandler objectrequest
: handler.requestcurrent_user
: handler.current_userlocale
: handler.locale_
: handler.locale.translatestatic_url
: handler.static_urlxsrf_form_html
: handler.xsrf_form_htmlreverse_url
: Application.reverse_url- 所有來自
ui_methods
和ui_modules``````Application
的設置項 - 所有傳遞給
render
或render_string
的關鍵詞
在構建實際應用程序時,你將可能會使用到Tornado模板的所有功能,尤其是模板繼承。 閱讀tornado.template
部分中有關這些功能的所有內容(包括UIDodules
在內的某些在tornado.web
模塊中實現的功能)
實際上Tornado模板在後臺將直接轉換爲Python語言。你在模板中包含的表達式將逐字複製到表示模板的Python函數中。 我們不會試圖阻止模板語言中的任何內容;我們創建模板時就爲了提供比其他相對嚴格的模板系統中所缺少的靈活性。因此,如果在模板表達式中編寫不受控制的內容,則在Python中執行模板時將會出現不可預知的錯誤。
默認情況下,使用tornado.escape.xhtml_escape
函數對所有模板輸出進行轉義。 可以通過將autoescape = None
傳遞給Application
或tornado.template.Loader
構造函數,可以進行全局的轉義開關設置,也可以使用{% autoescape None %}
指令的模板文件或在單個表達式中使用{% raw ...%}
替換{{...}}
達到關閉轉義的目的。另外,在所有位置中都可以使用轉義函數的名稱代替None
。
請注意,雖然Tornado的自動轉義有助於避免XSS漏洞,但不能保證在所有的情況下都有用。出現在某些位置的表達式(例如Javascript或CSS)可能需要額外的轉義。此外,必須注意始終在可能包含不可信內容的HTML屬性中使用雙引號和xhtml_escape,或者必須爲屬性使用單獨的轉義函數(可在http://wonko.com/post/html-escaping中查看示例)。
國際化
當前用戶的區域設置(無論它們是否登錄)始終在請求處理程序中以self.locale
的形式提供,在模板中始終以locale
的形式提供。語言環境的名稱(例如en_US
)儲存在locale.name
中,您可以使用Locale.translate
方法翻譯字符串。模板還有_()
這樣可用於字符串轉換的全局函數調用。 translate函數有兩種形式:
_("Translate this string")
它根據當前語言環境直接翻譯字符串,並且:
_("A person liked this", "%(num)d people liked this",
len(people)) % {"num": len(people)}
它根據第三個參數的值翻譯一個可以是單數或複數的字符串。在上面的示例中,如果len(people)
爲1,則將返回第一個字符串的翻譯,否則將返回第二個字符串的翻譯。
下面是一個恰當的國際化模板:
<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
。
UI模塊
Tornado支持UI模塊(UI modules),這將使你的應用可以更輕鬆地支持標準化、可複用的UI組件。 UI模塊就像用渲染頁面組件的特殊函數調用一樣,它們可以與自己的CSS和JavaScript打包在一起。
例如,如果你想要自己寫一個博客,並且希望在博客主頁和每個博客條目頁面上都顯示博客條目,則可以創建一個Entry
模塊以在所有頁面上渲染它們。首先,爲UI模塊創建一個Python模塊,例如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 %}
語句調用模塊。例如,你可以從home.html
調用Entry
模塊:
{% for entry in entries %}
{% module Entry(entry) %}
{% end %}
以及從entry.html
中調用:
{% module Entry(entry, show_comments=True) %}
模塊可以通過重寫embedded_css
,embedded_javascript
,javascript_files
或css_files
方法來包含自定義CSS和JavaScript函數:
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 ... %}
指令不同,模板模塊與其包含模板具有不同的命名空間——它們只能看到全局模板命名空間和它們自己的關鍵字參數。
上一篇:一個Tornado網絡應用的結構
下一篇:認證與安全