Tornado是Python的一款高人氣Web開發框架,這裏我們來展示使用Python的Tornado框架實現一個Web端圖書展示頁面的實例,通過該實例可以清楚地學習到Tornado的模板使用及整個Web程序的執行流程.
首先,爲什麼選擇Tornado:
1.高性能的網絡庫,這可以和gevent,twisted,libevent等做對。
提供了異步io支持,超時事件處理,在此基礎上提供了tcpserver,httpclient,尤其是curlhttpclient,
在現有http客戶端中肯定排第一。可以用來做爬蟲,遊戲服務器,據我所知業界已有使用tornado作爲遊戲服務器
2.web框架,這可以和django,flask對。
提供了路由,模板等web框架必備組件。與其他區別是tornado是異步的,天然適合長輪訓,
這也是friendfeed發明tornado的原因,當前flask也可以支持,但必須藉助gevent等
3.較爲完備的http服務器,這點可以和nginx,apache對比,
但只支持http1.0,所以使用nginx做前段不僅是爲了更好利用多核,也是讓其支持http1.1
4.完備的wsgi服務器,這可以和gunicore,gevent wsgi server做對比,
也就是說可以讓flask運行在tornado之上,讓tornado加速flask
5.提供了完備的websocket支持,這讓html5的遊戲等提供了便利。
像知乎長輪訓就是使用了websocket,但websocket手機支持的不是很好,
前段時間不得不使用定時ajax發送大量請求,期待手機瀏覽器趕快奮起直追
使用tornado創建一個簡單的圖書介紹頁
好了,言歸正傳,下面我們來看一下這個圖書介紹頁的代碼實現:
1.創建一個web服務的入口文件 blockmain.py
#coding:utf-8
import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.options
import os.path
import json
import urllib2
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render(
"index.html",
page_title = "Burt's Books ¦ Home",
header_text = "Welcome to Burt's Books!",
books = ['細說php','python','PHP','小時代']
)
class HelloModule(tornado.web.UIModule):
def render(self):
return'<h1>I am yyx and this is an information from module hello!</h1>'
class BookModule(tornado.web.UIModule):
def render(self,bookname):
doubanapi = r'https://api.douban.com/v2/book/'
searchapi = r'https://api.douban.com/v2/book/search?q='
searchurl = searchapi+bookname
searchresult = urllib2.urlopen(searchurl).read()
bookid = json.loads(searchresult)['books'][0]['id']
bookurl = doubanapi+bookid
injson = urllib2.urlopen(bookurl).read()
bookinfo = json.loads(injson)
return self.render_string('modules/book.html',book = bookinfo)
def embedded_javascript(self):
return "document.write(\"hi!\")"
def embedded_css(self):
return '''.book {background-color:#F5F5F5}
.book_body{color:red}
'''
def html_body(self):
return '<script>document.write("Hello!")</script>'
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers = [
(r'/',MainHandler),
],
template_path = os.path.join(os.path.dirname(__file__),'templates'),
static_path = os.path.join(os.path.dirname(__file__),'static'),
debug = True,
ui_modules={'Hello':HelloModule,'Book':BookModule}
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
說明一下,一些基本的MVC概念:
tornado也是通過pathinfo模式來匹配用戶的輸入來獲得參數,然後再調用相應的處理函數,它是通過爲各種匹配模式設定相應的class類來處理,比如我這裏就是通過class MainHandler來處理來自/的get請求
MainHandler把請求render渲染到index.html,參數在index.html中通過{{參數}}來調用
2.建立相應的模板,先創建一個基礎的父類main.html模板,創建templates目錄,在它下面創建main.html,這個模板只是定義了最基礎的網頁框架,裏面的具體內容由繼承於它的子類來具體實現
<html>
<head>
<title>{{ page_title }}</title>
<link rel="stylesheet" href="{{ static_url("css/style.css") }}" />
</head>
<body>
<div id="container">
<header>
{% block header %}<h1>Burt's Books</h1>{% end %}
</header>
<div id="main">
<div id="content">
{% block body %}{% end %}
</div>
</div>
<footer>
{% set mailLink = '<a href="mailto:[email protected]">Contact Us</a>' %}
{% set script = '<script>alert("hello")</script>' %}
{% block footer %}
<p>
For more information about our selection, hours or events, please email us at{% raw mailLink %}
<!-- {% raw script %} 這裏將原樣輸出,也就是會彈一個框-->
</p>
{% end %}
</footer>
</div>
<script src="{{ static_url("js/script.js") }}"></script>
</body>
</html>
這裏是定義了一個主框架,其中裏面的{% block header %}
Burt’s Books
{% end %}是爲了子類模板的繼承的塊(block),當子類繼承了這個main.html,具體這個塊裏寫什麼內容由子類來實現,不實現的話就使用父類的默認 值,如是這裏的Burt’s Books
,MainHandler類是render到一個index.html,那麼接下來寫一個index.html來繼承這 個父類{% extends "main.html" %}
{% block header %}
<h1>{{ header_text }}</h1>
{% end %}
{% block body %}
<div id="hello">
<p>Welcome to Burt's Books!</p>
{% module Hello() %}
{% for book in books %}
{% module Book(book) %}
{% end %}
<p>...</p>
</div>
{% end %}
簡單簡潔吧,這也是使用了繼承的好處,不用再重複寫父類的東西,只要實現父類的block內容即可
MainHandler類裏的render方法中的參數
page_title = "Burt's Books | Home",
header_text = "Welcome to Burt's Books!",
books = ['細說php','python','PHP','小時代']
將會通過參數傳送到這裏來
tornado的模板裏可以使用python的代碼,加上{% %}當使用if for while等要使用{% end %}結尾
代碼中{% module Book(book) %} 將會調用入口服務文件中的定義和’Book’所對應的模塊
ui_modules={‘Hello’:HelloModule,‘Book’:BookModule} 也就是BookModule,查看上面的BookModule定義
class BookModule(tornado.web.UIModule):
def render(self,bookname):
doubanapi = r'https://api.douban.com/v2/book/'
searchapi = r'https://api.douban.com/v2/book/search?q='
searchurl = searchapi+bookname
searchresult = urllib2.urlopen(searchurl).read()
bookid = json.loads(searchresult)['books'][0]['id']
bookurl = doubanapi+bookid
injson = urllib2.urlopen(bookurl).read()
bookinfo = json.loads(injson)
return self.render_string('modules/book.html',book = bookinfo)
BookModule 繼承自tornado.web.UIModule,UI模塊的使用是最後render_string()方法來把一個對象渲染到一個模板中去,我這裏簡單 的使用了豆瓣的圖書api,先通過search來查詢一下包含關鍵詞的圖書信息,返回第一條圖書的id,再使用book api來查詢該圖書的具體信息,將這個具體圖書的信息render到對應的模板
在templates 目錄下創建modules目錄,再下創建一個book.html,這裏是具體的book要顯示的內容框架
<div class="book">
<h3 class="book_title">{{ book["title"] }}</h3>
<a href="{{book['alt']}}" target="_blank"><p>點擊查看詳情</p></a>
{% if book["subtitle"] != "" %}
<h4 class="book_subtitle">{{ book["subtitle"] }}</h4>
{% end %}
<img src="{{ book["images"]["large"] }}" class="book_image"/>
<div class="book_details">
<div class="book_date_released">Released: {{ book["pubdate"]}}</div>
<h5>Description:</h5>
<div class="book_body">{% raw book["summary"] %}</div>
</div>
</div>
最後的文件目錄結構應該是這樣的
├── blockmain.py
└── templates
├── index.html
├── main.html
└── modules
└── book.html
程序的執行是這樣的:
先通過路徑‘/'來使用MainHandler類訪問index.html---->index.html繼承自 main.html---->index.html中的{% module Book(book) %}反過來查找blockmain.py中的Book對應的ui_modules---->ui_modules中將查詢得到的book對象內容渲 染到modules下的book.html中,這樣就把完整的內容呈現出來了,沒有做前端…… 通過python blockmain.py啓動服務,通過http://localhost:8000 來訪問得到如下的網頁
最後給大家推薦一個資源很全的python學習聚集地,[點擊進入],這裏有我收集以前學習心得,學習筆
記,還有一線企業的工作經驗,且給大定on零基礎到項目實戰的資料,大家也可以在下方,留言,把不
懂的提出來,大家一起學習進步