我們首先來談?wù)剋eb框架. web框架的本質(zhì)其實就是socket
服務(wù)端再加上業(yè)務(wù)邏輯處理, 比如像是Tornado
這樣的框架. 有一些框架則只包含業(yè)務(wù)邏輯處理, 例如Django
, bottle
, flask
這些框架, 它們的使用需要依賴包含socket
的第三方模塊(即 wsgiref
)來運行
在python中常見的web框架構(gòu)建模式有以下兩種:
- *
MVC
框架: * - 數(shù)據(jù)庫相關(guān)操作的
Models
- 視圖文件的
Views
- 業(yè)務(wù)邏輯的
Controllers
MTV
框架:- 數(shù)據(jù)庫相關(guān)操作的
Models
- 模板文件
Templates
- 業(yè)務(wù)邏輯的
Views
以上兩種只是命名不同, 所遵循的的思想也只是大同小異
在使用Tornado
框架前, 我們先使用wsgiref
再加上自己寫的業(yè)務(wù)邏輯自定義一個web框架
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server
def index():
return "This is index "
def news():
return "welcome to news "
URLS = {
'/index': index,
'/news': news,
}
def RunServer(rq, rp):
rp('200 OK', [('Content-Type', 'text/html')])
url = rq['PATH_INFO']
if url in URLS.keys():
ret = URLS[url]()
else:
ret = '404'
return ret
if __name__ == '__main__':
http = make_server('', 8000, RunServer)
http.serve_forever()
-
wsgiref
在py2中運行正常, 在py3中會報錯 -
http = make_server('', 8000, RunServer)
這里創(chuàng)建socket
服務(wù)端, 并傳入業(yè)務(wù)邏輯功能函數(shù)RunServer(rq, rp)
-
http.serve_forever()
啟動服務(wù)端, 阻塞進(jìn)程等待客戶端訪問, 一旦有訪問則執(zhí)行RunServer(rq, rp)
方法 -
RunServer(rq, rp)
該方法中rq
封裝了請求信息,rp
封裝了響應(yīng)信息 -
url = rq['PATH_INFO']
獲取請求的url連接地址 -
ret = URLS[url]()
根據(jù)請求的url執(zhí)行對應(yīng)的函數(shù) - 當(dāng)我們將執(zhí)行的
index()
和news()
功能函數(shù)放進(jìn)Controllers
業(yè)務(wù)邏輯處理模塊, 將返回結(jié)果ret
改為文件讀寫后的內(nèi)容, 并將該文件放置到Views
或者Template
模塊中, 就形成了最基礎(chǔ)版本的MVC
和MTV
框架
接下來我們使用Tornado
實現(xiàn)一個簡陋的任務(wù)表功能demo
目錄結(jié)構(gòu)
**commons.css
文件內(nèi)容: **
.body {
margin: 0;
background-color: cornflowerblue;
}
**index.html
文件內(nèi)容: **
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>S1</title>
<link rel="stylesheet" href="../static/commons.css">
</head>
<body>
<form method="post">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
<h1>內(nèi)容展示</h1>
<ul>
{% for item in contents %}
<li>{{item}}</li>
{% end %}
</ul>
</body>
</html>
**index.py
文件內(nèi)容: **
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web, tornado.ioloop
class MyHandle(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render("index.html", contents=CONTENTS_LIST)
def post(self, *args, **kwargs):
CONTENTS_LIST.append(self.get_argument('name'))
self.render('index.html', contents=CONTENTS_LIST)
if __name__ == '__main__':
CONTENTS_LIST = []
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': 'static/',
}
application = tornado.web.Application([
(r"/index", MyHandle)
], **settings)
application.listen(80)
tornado.ioloop.IOLoop.instance().start()
客戶端第一次訪問
第一次輸入提交
-
CONTENTS_LIST = []
為存放的是輸入框輸入的內(nèi)容 -
settings
字典表示的是配置文件 -
'template_path': 'template'
模板文件的存放位置 -
'static_path': 'static'
靜態(tài)文件的存放位置, 靜態(tài)文件必須聲明, 否則瀏覽器無法找到靜態(tài)文件 -
'static_url_prefix': 'static/'
靜態(tài)文件前綴, 減少每個文件引入都要加前綴的麻煩
application = tornado.web.Application([
(r"/index", MyHandle)
], **settings)
根據(jù)瀏覽器的url確定其對應(yīng)的處理類并生成該類的對象
- `application.listen(80)` 設(shè)置服務(wù)端的監(jiān)聽端口
- `tornado.ioloop.IOLoop.instance().start()` 阻塞服務(wù)端進(jìn)程, 等待客戶端的訪問
- 客戶端第一次訪問調(diào)用的是`MyHandle`類中的`get(self, *args, **kwargs)`方法, 服務(wù)端向客戶端返回`index.html`文件
- 客戶端瀏覽器接受到`index.html`文件之后, 在輸入框中輸入內(nèi)容并提交之后會調(diào)用`post(self, *args, **kwargs)`, 并將輸入的內(nèi)容追加到
- `self.get_argument('name')` 獲取指定參數(shù)的內(nèi)容
`CONTENTS_LIST`中, 服務(wù)端返回`index.html`, 返回過程中`Toranado`
會將`CONTENTS_LIST` 的內(nèi)容渲染到`index.html`之后才會發(fā)給客戶端瀏覽器
**python中的模板引擎本質(zhì)上是將`html`文件轉(zhuǎn)換成一段`python`函數(shù)字符串, 再通過`compile`和`exec`將該函數(shù)執(zhí)行, 以此來進(jìn)行模板渲染**
*現(xiàn)在我們介紹一下模板引擎的使用: *

**`uimethod.py`文件如下: **
```python
#!/usr/bin/env python
# -*- coding:utf-8 -*-
def test_uimethod(self):
return "uimethod"
**uimodule.py
文件如下: **
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.web import UIModule
class MyClass(UIModule):
def render(self, *args, **kwargs):
return "uimodule"
**index.py
文件如下: **
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web, tornado.ioloop
import uimethod as ut
import uimodule as ud
class MyHandle(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render("index.html", ag="this is ag", contents=CONTENTS_LIST)
def post(self, *args, **kwargs):
CONTENTS_LIST.append(self.get_argument('name'))
self.render('index.html', contents=CONTENTS_LIST)
if __name__ == '__main__':
CONTENTS_LIST = []
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': 'static/',
'ui_methods': ut,
'ui_modules': ud
}
application = tornado.web.Application([
(r"/index", MyHandle)
], **settings)
application.listen(80)
tornado.ioloop.IOLoop.instance().start()
**index.html
文件如下: **
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>S1</title>
<link rel="stylesheet" href='{{static_url("commons.css")}}'>
</head>
<body>
<h1>{{ag}}</h1>
<h1>{{test_uimethod()}}</h1>
<h1>{%module MyClass()%}</h1>
<form method="post">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
<h1>內(nèi)容展示</h1>
<ul>
{% for item in contents %}
<li>{{item}}</li>
{% end %}
</ul>
<hr>
</body>
</html>
*我們看看客戶端訪問的結(jié)果: *
訪問結(jié)果
- 模板引擎中的
{{key}}
表示取key
對應(yīng)的值, 當(dāng)key
為函數(shù)時候執(zhí)行該函數(shù)并取該函數(shù)結(jié)果. 例如index.html
文件中的<h1>{{ag}}</h1>
實際上取得是index.py
的self.render("index.html", ag="this is ag", contents=CONTENTS_LIST)
中的參數(shù)ag
的值 -
<h1>{{test_uimethod()}}</h1>
這里執(zhí)行的是自定義函數(shù), 我們將這個自定義函數(shù)寫在uimethod.py
文件中, 并且在index.py
文件中導(dǎo)入, 然后將index.py
文件中的settings
配置增加一行'ui_methods': ut
, 該行內(nèi)容表示模板引擎可執(zhí)行自定義函數(shù) - 模板引擎中的
{%%}
可用于循環(huán)語句和條件語言以及自定義類的執(zhí)行,{% for item in contents %}
此處正是用于循環(huán)遍歷contents
中的內(nèi)容 -
<h1>{%module MyClass()%}</h1>
此處表示模板引擎執(zhí)行自定義類, 該類的文件對應(yīng)的是uimodule.py
文件, 我們需要在index.py
的settings
中增加一行'ui_modules': ud
, 改行表示模板引擎可使用自定義類 - 注意, 我們將
index.html
文件引入css
的方式改為了<link rel="stylesheet" href='{{static_url("commons.css")}}'>
,static_url()
是模板引擎內(nèi)置的自定義函數(shù), 用該函數(shù)引入css
文件時候, 僅當(dāng)css
文件內(nèi)容發(fā)生變化時候, 瀏覽器才會重新緩存該css
文件
考慮到篇幅太長不容易閱讀, 筆者這里將關(guān)于Tornado
框架的cookie
知識, 自定義session
的使用 路由系統(tǒng),以及模板引擎高級部分放在后期文章分篇共享