<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在第一章中,我們學習了使用Tornado創建一個Web應用的基礎知識。包括處理函數、HTTP方法以及Tornado框架的總體結構。在這章中,我們將學習一些你在創建Web應用時經常會用到的更強大的功能。 和大多數Web框架一樣,Tornado的一個重要目標就是幫助你更快地編寫程序,盡可能整潔地復用更多的代碼。盡管Tornado足夠靈活,可以使用幾乎所有Python支持的模板語言,Tornado自身也提供了一個輕量級、快速并且靈活的模板語言在tornado.template模塊中。 [TOC=2,3] ## 2.1 簡單示例:Poem Maker Pro 讓我們以一個叫作Poem Maker Pro的簡單例子開始。Poem Maker Pro這個Web應用有一個讓用戶填寫的HTML表單,然后處理表單的結果。代碼清單2-1是它的Python代碼。 代碼清單2-1 簡單表單和模板:poemmaker.py ~~~ import os.path import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class IndexHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') class PoemPageHandler(tornado.web.RequestHandler): def post(self): noun1 = self.get_argument('noun1') noun2 = self.get_argument('noun2') verb = self.get_argument('verb') noun3 = self.get_argument('noun3') self.render('poem.html', roads=noun1, wood=noun2, made=verb, difference=noun3) if __name__ == '__main__': tornado.options.parse_command_line() app = tornado.web.Application( handlers=[(r'/', IndexHandler), (r'/poem', PoemPageHandler)], template_path=os.path.join(os.path.dirname(__file__), "templates") ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() ~~~ 除了poemmaker.py,你還需要將代碼清單2-2和代碼清單2-3中的兩個文件加入到templates子文件夾中。 代碼清單2-2 Poem Maker表單:index.html ~~~ <!DOCTYPE html> <html> <head><title>Poem Maker Pro</title></head> <body> <h1>Enter terms below.</h1> <form method="post" action="/poem"> <p>Plural noun<br><input type="text" name="noun1"></p> <p>Singular noun<br><input type="text" name="noun2"></p> <p>Verb (past tense)<br><input type="text" name="verb"></p> <p>Noun<br><input type="text" name="noun3"></p> <input type="submit"> </form> </body> </html> ~~~ 代碼清單2-3 Poem Maker模板:poem.html ~~~ <!DOCTYPE html> <html> <head><title>Poem Maker Pro</title></head> <body> <h1>Your poem</h1> <p>Two {{roads}} diverged in a {{wood}}, and I—<br> I took the one less travelled by,<br> And that has {{made}} all the {{difference}}.</p> </body> </html> ~~~ 在命令行執行下述命令: ~~~ $ python poemmaker.py --port=8000 ~~~ 現在,在瀏覽器中打開[http://localhost:8000](http://localhost:8000/)。當瀏覽器請求根目錄(/)時,Tornado程序將渲染index.html,展示如圖2-1所示的簡單HTML表單。 ![圖2-1](https://box.kancloud.cn/2015-09-04_55e96c0e463ab.jpg) 圖2-1 Poem Maker Pro:輸入表單 這個表單包括多個文本域(命名為noun1、noun2等),其中的內容將在用戶點擊"Submit"按鈕時以POST請求的方式送到`/poem`。現在往里面填寫東西然后點擊提交吧。 為了響應這個POST請求,Tornado應用跳轉到poem.html,插入你在表單中填寫的值。結果是Robert Frost的詩《The Road Not Taken》的輕微修改版本。圖2-2展示了這個結果。 ![圖2-2](https://box.kancloud.cn/2015-09-04_55e96c1f9ec7b.jpg) 圖2-2 Poem Maker Pro:輸出 ### 2.1.1 渲染模板 從結構上講,poemmaker.py和[第一章](http://dockerpool.com/static/books/introduction_to_tornado_cn/ch1.html)中的例子很相似。我們定義了幾個RequestHandler子類并把它們傳給tornado.web.Application對象。那么有什么不一樣的地方呢?首先,我們向Application對象的__init__方法傳遞了一個template_path參數。 ~~~ template_path=os.path.join(os.path.dirname(__file__), "templates") ~~~ template_path參數告訴Tornado在哪里尋找模板文件。我們將在本章和[第三章](http://dockerpool.com/static/books/introduction_to_tornado_cn/ch3.html)中講解其確切性質和語法,而它的基本要點是:模板是一個允許你嵌入Python代碼片段的HTML文件。上面的代碼告訴Python在你Tornado應用文件同目錄下的templates文件夾中尋找模板文件。 一旦我們告訴Tornado在哪里找到模板,我們可以使用RequestHandler類的render方法來告訴Tornado讀入模板文件,插入其中的模版代碼,并返回結果給瀏覽器。比如,在IndexHandler中,我們發現了下面的語句: ~~~ self.render('index.html') ~~~ 這段代碼告訴Tornado在templates文件夾下找到一個名為index.html的文件,讀取其中的內容,并且發送給瀏覽器。 ### 2.1.2 填充 實際上index.html完全不能稱之為"模板",它所包含的完全是已編寫好的HTML標記。這可以是模板的一個不錯的使用方式,但在更通常的情況下我們希望HTML輸出可以結合我們的程序傳入給模板的值。模板poem.html使用PoemPageHandler渲染,是這種方式的一個很好的例子。讓我們看看它是如何工作的吧。 在poem.html中,你可以看到模板中有一些被雙大括號({{和}})括起來的字符串,就像這樣: ~~~ <p>Two {{roads}} diverged in a {{wood}}, and I—<br/> I took the one less travelled by,<br> And that has {{made}} all the {{difference}}.</p> ~~~ 在雙大括號中的單詞是占位符,當我們渲染模板時希望以實際值代替。我們可以使用向render函數中傳遞關鍵字參數的方法指定什么值將被填充到HTML文件中的對應位置,其中關鍵字對應模板文件中占位符的名字。下面是在PoemPageHandler中相應的代碼部分: ~~~ noun1 = self.get_argument('noun1') noun2 = self.get_argument('noun2') verb = self.get_argument('verb') noun3 = self.get_argument('noun3') self.render('poem.html', roads=noun1, wood=noun2, made=verb, difference=noun3) ~~~ 在這里,我們告訴模板使用變量noun1(該變量是從get_argument方法取得的)作為模板中roads的值,noun2作為模板中wood的值,依此類推。假設用戶在表單中按順序鍵入了pineapples、grandfather clock、irradiated和supernovae,那么結果HTML將會如下所示: ~~~ <p>Two pineapples diverged in a grandfather clock, and I—<br> I took the one less travelled by,<br> And that has irradiated all the supernovae.</p> ~~~ ## 2.2 模板語法 既然我們已經看到了一個模板在實際應用中的簡單例子,那么讓我們深入地了解它們是如何工作的吧。Tornado模板是被Python表達式和控制語句標記的簡單文本文件。Tornado的語法非常簡單直接。熟悉Django、Liquid或其他相似框架的用戶會發現它們非常相似,很容易學會。 在2.1節中,我們展示了如何在一個Web應用中使用render方法傳送HTML給瀏覽器。你可以在Tornado應用之外使用Python解釋器導入模板模塊嘗試模板系統,此時結果會被直接輸出出來。 ~~~ >>> from tornado.template import Template >>> content = Template("<html><body><h1>{{ header }}</h1></body></html>") >>> print content.generate(header="Welcome!") <html><body><h1>Welcome!</h1></body></html> ~~~ ### 2.2.1 填充表達式 在代碼清單2-1中,我們演示了填充Python變量的值到模板的雙大括號中的使用。實際上,你可以將任何Python表達式放在雙大括號中。Tornado將插入一個包含任何表達式計算結果值的字符串到輸出中。下面是幾個可能的例子: ~~~ >>> from tornado.template import Template >>> print Template("{{ 1+1 }}").generate() 2 >>> print Template("{{ 'scrambled eggs'[-4:] }}").generate() eggs >>> print Template("{{ ', '.join([str(x*x) for x in range(10)]) }}").generate() 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 ~~~ ### 2.2.2 控制流語句 你同樣可以在Tornado模板中使用Python條件和循環語句。控制語句以{%和%}包圍,并以類似下面的形式被使用: ~~~ {% if page is None %} ~~~ 或 ~~~ {% if len(entries) == 3 %} ~~~ 控制語句的大部分就像對應的Python語句一樣工作,支持if、for、while和try。在這些情況下,語句塊以{%開始,并以%}結束。 所以這個模板: ~~~ <html> <head> <title>{{ title }}</title> </head> <body> <h1>{{ header }}</h1> <ul> {% for book in books %} <li>{{ book }}</li> {% end %} </ul> </body> </html> ~~~ 當被下面這個處理函數調用時: ~~~ class BookHandler(tornado.web.RequestHandler): def get(self): self.render( "book.html", title="Home Page", header="Books that are great", books=[ "Learning Python", "Programming Collective Intelligence", "Restful Web Services" ] ) ~~~ 將會渲染得到下面的輸出: ~~~ <html> <head> <title>Home Page</title> </head> <body> <h1>Books that are great</h1> <ul> <li>Learning Python</li> <li>Programming Collective Intelligence</li> <li>Restful Web Services</li> </ul> </body> </html> ~~~ 不像許多其他的Python模板系統,Tornado模板語言的一個最好的東西是在if和for語句塊中可以使用的表達式沒有限制。因此,你可以在你的模板中執行所有的Python代碼。 同樣,你也可以在你的控制語句塊中間使用`{% set foo = 'bar' %}`來設置變量。你還有很多可以在控制語句塊中做的事情,但是在大多數情況下,你最好使用UI模塊來做更復雜的劃分。我們稍后會更詳細的看到這一點。 ### 2.2.3 在模板中使用函數 Tornado在所有模板中默認提供了一些便利的函數。它們包括: ##### escape(s) 替換字符串s中的&、為他們對應的HTML字符。 ##### url_escape(s) 使用urllib.quote_plus替換字符串s中的字符為URL編碼形式。 ##### json_encode(val) 將val編碼成JSON格式。(在系統底層,這是一個對json庫的dumps函數的調用。查閱相關的文檔以獲得更多關于該函數接收和返回參數的信息。) ##### squeeze(s) 過濾字符串s,把連續的多個空白字符替換成一個空格。 在Tornado 1.x中,模版不是被自動轉義的。在Tornado 2.0中,模板被默認為自動轉義(并且可以在Application構造函數中使用autoscaping=None關閉)。在不同版本的遷移時要注意向后兼容。 在模板中使用一個你自己編寫的函數也是很簡單的:只需要將函數名作為模板的參數傳遞即可,就像其他變量一樣。 ~~~ >>> from tornado.template import Template >>> def disemvowel(s): ... return ''.join([x for x in s if x not in 'aeiou']) ... >>> disemvowel("george") 'grg' >>> print Template("my name is {{d('mortimer')}}").generate(d=disemvowel) my name is mrtmr ~~~ ## 2.3 復雜示例:The Alpha Munger 在代碼清單2-4中,我們把在這一章中談論過的所有東西都放了進來。這個應用被稱為The Alpha Munger。用戶輸入兩個文本:一個"源"文本和一個"替代"文本。應用會返回替代文本的一個副本,并將其中每個單詞替換成源文本中首字母相同的某個單詞。圖2-3展示了要填的表單,圖2-4展示了結果文本。 這個應用包括四個文件:main.py(Tornado程序)、style.css(CSS樣式表文件)、index.html和munged.html(Tornado模板)。讓我們看看代碼吧: 代碼清單2-4 復雜表單和模板:main.py ~~~ import os.path import random import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class IndexHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') class MungedPageHandler(tornado.web.RequestHandler): def map_by_first_letter(self, text): mapped = dict() for line in text.split('\r\n'): for word in [x for x in line.split(' ') if len(x) > 0]: if word[0] not in mapped: mapped[word[0]] = [] mapped[word[0]].append(word) return mapped def post(self): source_text = self.get_argument('source') text_to_change = self.get_argument('change') source_map = self.map_by_first_letter(source_text) change_lines = text_to_change.split('\r\n') self.render('munged.html', source_map=source_map, change_lines=change_lines, choice=random.choice) if __name__ == '__main__': tornado.options.parse_command_line() app = tornado.web.Application( handlers=[(r'/', IndexHandler), (r'/poem', MungedPageHandler)], template_path=os.path.join(os.path.dirname(__file__), "templates"), static_path=os.path.join(os.path.dirname(__file__), "static"), debug=True ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() ~~~ ![圖2-3](https://box.kancloud.cn/2015-09-04_55e96c20cbdb9.jpg) 圖2-3 Alpha Munger:輸入表單 ![圖2-4](https://box.kancloud.cn/2015-09-04_55e96c212fec8.jpg) 圖2-4 Alpha Munger:輸出 記住Application構造函數中的static_path參數。我們將在下面進行詳細的介紹,但是現在你所需要知道的就是static_path參數指定了你應用程序放置靜態資源(如圖像、CSS文件、JavaScript文件等)的目錄。另外,你還需要在templates文件夾下添加index.html和munged.html這兩個文件。 代碼清單2-5 Alpha Munger表單:index.html ~~~ <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="{{ static_url("style.css") }}"> <title>The Alpha Munger</title> </head> <body> <h1>The Alpha Munger</h1> <p>Enter two texts below. The replacement text will have its words replaced by words beginning with the same letter in the source text.</p> <form method="post" action="/poem"> <p>Source text<br> <textarea rows=4 cols=55 name="source"></textarea></p> <p>Text for replacement<br> <textarea rows=4 cols=55 name="change"></textarea></p> <input type="submit"> </form> </body> </html> ~~~ 代碼清單2-6 Alpha Munger模板:munged.html ~~~ <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="{{ static_url("style.css") }}"> <title>The Alpha Munger</title> </head> <body> <h1>Your text</h1> <p> {% for line in change_lines %} {% for word in line.split(' ') %} {% if len(word) > 0 and word[0] in source_map %} <span class="replaced" title="{{word}}">{{ choice(source_map[word[0]]) }}</span> {% else %} <span class="unchanged" title="unchanged">{{word}}</span> {% end %} {% end %} <br> {% end %} </p> </body> </html> ~~~ 最后,將代碼清單2-7中的內容寫到static子目錄下的style.css文件中。 代碼清單2-7 Alpha Munger樣式表:style.css ~~~ body { font-family: Helvetica,Arial,sans-serif; width: 600px; margin: 0 auto; } .replaced:hover { color: #00f; } ~~~ ### 2.3.1 它如何工作 這個Tornado應用定義了兩個請求處理類:IndexHandler和MungedPageHandler。IndexHandler類簡單地渲染了index.html中的模板,其中包括一個允許用戶POST一個源文本(在source域中)和一個替換文本(在change域中)到`/poem`的表單。 MungedPageHandler類用于處理到`/poem`的POST請求。當一個請求到達時,它對傳入的數據進行一些基本的處理,然后為瀏覽器渲染模板。map_by_first_letter方法將傳入的文本(從source域)分割成單詞,然后創建一個字典,其中每個字母表中的字母對應文本中所有以其開頭的單詞(我們將其放入一個叫作source_map的變量)。再把這個字典和用戶在替代文本(表單的change域)中指定的內容一起傳給模板文件munged.html。此外,我們還將Python標準庫的random.choice函數傳入模板,這個函數以一個列表作為輸入,返回列表中的任一元素。 在munged.html中,我們迭代替代文本中的每行,再迭代每行中的每個單詞。如果當前單詞的第一個字母是source_map字典的一個鍵,我們使用random.choice函數從字典的值中隨機選擇一個單詞并展示它。如果字典的鍵中沒有這個字母,我們展示源文本中的原始單詞。每個單詞包括一個span標簽,其中的class屬性指定這個單詞是替換后的(class="replaced")還是原始的(class="unchanged")。(我們還將原始單詞放到了span標簽的title屬性中,以便于用戶在鼠標經過單詞時可以查看是什么單詞被替代了。你可以在圖2-5中看到這個動作。) ![圖2-5](https://box.kancloud.cn/2015-09-04_55e96c21d147f.jpg) 圖2-5 含有被替換單詞提示的Alpha Munger 在這個例子中,你可能注意到了debug=True的使用。它調用了一個便利的測試模式:tornado.autoreload模塊,此時,一旦主要的Python文件被修改,Tornado將會嘗試重啟服務器,并且在模板改變時會進行刷新。對于快速改變和實時更新這非常棒,但不要再生產上使用它,因為它將防止Tornado緩存模板! ### 2.3.2 提供靜態文件 當編寫Web應用時,你總希望提供像樣式表、JavaScript文件和圖像這樣不需要為每個文件編寫獨立處理函數的"靜態內容"。Tornado提供了幾個有用的捷徑來使其變得容易。 #### 2.3.2.1 設置靜態路徑 你可以通過向Application類的構造函數傳遞一個名為static_path的參數來告訴Tornado從文件系統的一個特定位置提供靜態文件。Alpha Munger中的相關代碼片段如下: ~~~ app = tornado.web.Application( handlers=[(r'/', IndexHandler), (r'/poem', MungedPageHandler)], template_path=os.path.join(os.path.dirname(__file__), "templates"), static_path=os.path.join(os.path.dirname(__file__), "static"), debug=True ) ~~~ 在這里,我們設置了一個當前應用目錄下名為static的子目錄作為static_path的參數。現在應用將以讀取static目錄下的filename.ext來響應諸如/static/filename.ext的請求,并在響應的主體中返回。 #### 2.3.2.2 使用static_url生成靜態URL Tornado模板模塊提供了一個叫作static_url的函數來生成static目錄下文件的URL。讓我們來看看在index.html中static_url的調用的示例代碼: ~~~ <link rel="stylesheet" href="{{ static_url("style.css") }}"> ~~~ 這個對static_url的調用生成了URL的值,并渲染輸出類似下面的代碼: ~~~ <link rel="stylesheet" href="/static/style.css?v=ab12"> ~~~ 那么為什么使用static_url而不是在你的模板中硬編碼呢?有如下幾個原因。其一,static_url函數創建了一個基于文件內容的hash值,并將其添加到URL末尾(查詢字符串的參數v)。這個hash值確保瀏覽器總是加載一個文件的最新版而不是之前的緩存版本。無論是在你應用的開發階段,還是在部署到生產環境使用時,都非常有用,因為你的用戶不必再為了看到你的靜態內容而清除瀏覽器緩存了。 另一個好處是你可以改變你應用URL的結構,而不需要改變模板中的代碼。例如,你可以配置Tornado響應來自像路徑/s/filename.ext的請求時提供靜態內容,而不是默認的/static路徑。如果你使用static_url而不是硬編碼的話,你的代碼不需要改變。比如說,你想把靜態資源從我們剛才使用的/static目錄移到新的/s目錄。你可以簡單地改變靜態路徑由static變為s,然后每個使用static_url包裹的引用都會被自動更新。如果你在每個引用靜態資源的文件中硬編碼靜態路徑部分,你將不得不手動修改每個模板。 ### 2.3.3 模板的下一步 到目前為止,你已經能夠處理Tornado模板系統的簡單功能了。對于像Alpha Munger這樣簡單的Web應用而言,基礎的功能對你而言足夠用了。但是我們在模板部分的學習并沒有結束。Tornado在塊和模塊的形式上仍然有一些技巧,這兩個功能使得編寫和維護復雜的Web應用更加簡單。我們將在第三章中看到這些功能。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看