首頁  >  文章  >  後端開發  >  使用Python的Tornado框架實作一個Web端圖書展示頁面

使用Python的Tornado框架實作一個Web端圖書展示頁面

WBOY
WBOY原創
2016-08-04 08:55:531912瀏覽

首先,為什麼選擇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&#63;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:contact@burtsbooks.com">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&#63;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 來存取得到如下的網頁

2016711175031811.png (913×639)

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn