Tornado Web Framework – Hello Tornado、Template機制 (整合Bootstrap為例)

Tornado Web Framework – Hello Tornado、Template機制 (整合Bootstrap為例)

Python的知名Web框架有Django,Flask(Mirco Web Framework) ,應該還有一脫拉庫…今天我要試作的是來自於Facebook的開源Web框架.. Tornado  <–官網連結

tornado原本是Bret Taylor和其他人員為FriendFeed這一家公司所設計開發的Web服務框架,後來才被Facebook併購並開源了該專案。Tornado不同於傳統的web服務器框架,從設計之初就考http://35.194.140.171/wordpress/?p=203&preview=true慮到了高性能的需求,最大的目標為解決C10K的問題。除此之外,更兼顧了處理安全性、用戶驗證、外部服務異步交互的工具,包含跟OAuth機制、web socket都有完整的機制可以快速實現在Web服務器上的高性能應用服務。

延伸閱讀:https://mirrors.segmentfault.com/itt2zh/ch1.html

 

1.創建一個最簡單的Web服務

import webbrowser

from tornado import web
from tornado.ioloop import IOLoop
import tornado.web

from tornado.options import define, options
define("port", default=9999, help="run on the given port", type=int)

class HomeHandler( tornado.web.RequestHandler ):
    def get(self):
        self.write("<h1>hello , paul, tornado!!</h1>")

if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", HomeHandler),
    ],debug=True)

    application.listen(options.port)
    webbrowser.open( url="http://localhost:9999", new=True )
    IOLoop.current().start()

hello world的範例其實很簡單,創建一個test.py,直接定義一個Handler繼承自RequestHandler,先實作一個get行為(這些行為預設基於http的method,get, post, put, delete)。最上面還有定義一個port:9999的設定,等下下面啟動服務器的時候會用到,在get的實作中,直接write出”<h1>hello , paul, tornado!!</h1>”。

而預設程式中為了開發方便,直接在程式啟動的當下,一併開啟Browser(這個好像是模仿visual studio..),並開啟9999 port。

跑起來如願以償,但是這樣一個極度簡單的畫面渲染,顯然無法滿足現今動態網站的需求了,同時將網頁樣式引入程式碼(hard code html碼)並不是高明的作法。接下來要介紹tornado的樣版引擎,來達成頁面元素與後端程式的”觀注點分離”

2.引入樣版

以上題為例,看到顯示的名字可能需要動態去別的地方,可能來自於資料庫或使用者輸入,其他api等等,但是其他歡迎的字詞在這邊是固定的,不需要由動態程式綁死,為了抽換掉這個部分,需要定義樣版檔案,首先建立一個test.html檔案,並把原本寫死的html碼,搬移到該檔案,同時把原先名字的部分,抽出來變成{{name}},這{{名稱}}裡面的名稱可以自行定義

<h1>hello , {{name}}, tornado!!</h1>

同時在原本的handler這邊,調整一下寫法,把self.write變成self.render,並把樣版檔名作為參數,另外再加入剛剛約定好的名稱的name與value

class HomeHandler( tornado.web.RequestHandler ):
    def get(self):
        self.render("test.html", name="mido")

看起來這樣動態綁定的效果就是我要的,這一步立即將頁面樣式與動態程式分離成兩個部分,未來,若要改到html的樣式,像是字型大小、排版,都可以透過修改test.html檔就好了

例如:

<div>
    Hello , <font color="red">{{name}}</font><br>
    <p>Welcome to tornado!!</p>
</div>

然而,現代的網站通常不是這麼陽春的只有幾行字,若沒有美美的外觀,順眼的排版,適中的字型,還真的很難閱讀的下去,網頁的停留率肯定不高

因此當網頁內容愈來愈豐富,網站提供愈來愈多元的內容以後,希望網頁能帶給我們一致性的體驗,有同樣的header、footer、導覽列..etc,那若每次在網站中新增一個樣式html檔案後,是否可以不要重覆貼上這些區塊的html呢?當然可以!要用到繼承!!

3.樣版的進階玩法

首先先切出base.html作為網頁的基本架構,後續新增的網頁我都希望在這個架構下去延伸

<div>
    <h1>我的個人網站</h1>
</div>
<div>
    {% block content %}{% end %}
</div>
<div>
    <a href="http://paulfun.net">我的blog</a>
    <a href="emailto:[email protected]">聯絡我</a>
</div>
其中:{% block content %}{% end %}是用來約定,讓繼承的樣式檔去定義內容的標籤

test.html修改成這樣:
首先我宣告繼承base.html:方法是{% extends base.html %} 
註:類似asp.net mvc的_layout定義
網頁區塊要加入到{% block content %}網頁內容{% end %}之內。(註:若定義在標籤之外的,不會錯,但也不會顯示出來)
{% extends base.html %}
{% block content %}
<div>
    Hello , <font color="red">{{name}}</font><br>
    <p>Welcome to tornado!!</p>

    web page content!!

</div>
{% end %}

同樣的程式跑起來看看

這次成功的將header、footer、content成功的分離了原始的單一檔案,達到共用樣式效果

這是一種抽象化的概念,抽成base.html的效果是希望將共用的部分抽成全域,這可以省掉維護網頁架構、內容的許多工

但是如何去reuse網頁的區塊看起來還沒有說明到,像是瀏覽購物網站,商品分類導覽,推薦商品清單,排行榜常常在網頁中形影不離,

但是像是排行榜雖然在許多頁面呈現,但不是全域的,例如,結帳畫面就不需要有

每個頁面的排行榜位置也有可能有不同的地方。以目前這個三分法的網頁架構的例子,當HTML內容愈來愈多、複雜,我是否有辦法將header、footer再抽出去做管理?

抽出去看起來很簡單,就是創建一個header.html與footer.html,然後在原本的base.html加入include語法

<div>
    <h1>我的個人網站</h1>
</div>
<div>
    {% block content %}{% end %}
</div>

{% include footer.html %}

再度跑起來,內容一樣,但是一部分區塊透過這樣子分離原本的檔案,這類似元件化的技巧,讓我可以在其他網頁中組裝這些元件而不用重覆性的撰寫程式(程式中最大的詬病的就是重工)

註:include類似asp.net mvc的partial.view定義

 

4.美化它,加入bootstrap的js、css路徑參考  –> bootstrap套件取得

以往會將css/js定義在header來reference,現在為了套用bootstrap,加入了js/css目錄,並download放入了bootstrap的css與js檔,再加上最popular的jquery

__base.html

<html>
<head>
    <script src="js/jquery-1.12.4.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <!-- Bootstrap core CSS -->
    <link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    {% include __header.html %}

    {% block content %}{% end %}

</body>
</html>

那tornado的網站路徑下又要如何來定義這些外部檔案呢?

假如現在的網站架構如下:

在test.py中可綁定StaticFileHanler

test.py

import os
import webbrowser

from tornado import web
from tornado.ioloop import IOLoop
import tornado.web

from tornado.options import define, options
define("port", default=9999, help="run on the given port", type=int)

class HomeHandler( tornado.web.RequestHandler ):
    def get(self):
        self.render("test.html", name="Friend")

ROOT_PATH = os.path.dirname(os.path.abspath(
    __file__))

if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", HomeHandler),
        (r"/js/(.*)", web.StaticFileHandler, {"path": os.path.join(ROOT_PATH, "js")}),
        (r"/css/(.*)", web.StaticFileHandler, {"path": os.path.join(ROOT_PATH, "css")}),
    ],debug=True)

    application.listen(options.port)
    webbrowser.open( url="http://localhost:9999", new=True )
    IOLoop.current().start()

這邊的例子,將StaticFileHander給定指定的路徑,包含css與js,可以將server啟動的相對路徑指定給ROOT_PATH,並動態組合相對路徑css與js目錄給handler

__header.html

<nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">我的個人網站</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="http://paulfun.net">我的blog</a></li>
            <li><a href="mailto:[email protected]">Contact</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

這邊套用了bootstrap的範例,調整了header與base的結構,這邊我也將一些共用或全域的樣式檔,以__命名開頭,以作為區別

套用bootstrap就是縱使我工程屍美感0分,但套用這套件的網站,至少有及格的美觀程度,而且連RWD(Responsive Web Design)通通都送給你

當然,他還有很多樣式定義,詳情都可以看它的官網的範例

 

若是要快速實現一個RWD網站,這是我最常用的套件了~

以上大至記錄了我在tornado web框架下的一些試作過程,然而tornado做為web framework

我們一樣可以很輕易的實現如同我之前在asp.net mvc的功能

我必竟是.net出身,很容易地就會用以前的方式來詢問Python如何達到什麼功能

然而tornado,它不僅僅是web framework,要實作restful api , web socket server都輕而易舉。

這些就待下回分曉吧…

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *