咱們首先來談談web框架. web框架的本質其實就是socket
服務端再加上業務邏輯處理, 好比像是Tornado
這樣的框架. 有一些框架則只包含業務邏輯處理, 例如Django
, bottle
, flask
這些框架, 它們的使用須要依賴包含socket
的第三方模塊(即 wsgiref
)來運行
在python中常見的web框架構建模式有如下兩種: css
MVC
框架:
Models
Views
Controllers
MTV
框架:
Models
Templates
Views
以上兩種只是命名不一樣, 所遵循的的思想也只是大同小異html
在使用Tornado
框架前, 咱們先使用wsgiref
再加上本身寫的業務邏輯自定義一個web框架python
#!/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)
這裏建立socket
服務端, 並傳入業務邏輯功能函數RunServer(rq, rp)
http.serve_forever()
啓動服務端, 阻塞進程等待客戶端訪問, 一旦有訪問則執行RunServer(rq, rp)
方法RunServer(rq, rp)
該方法中rq
封裝了請求信息, rp
封裝了響應信息
url = rq['PATH_INFO']
獲取請求的url鏈接地址ret = URLS[url]()
根據請求的url執行對應的函數index()
和news()
功能函數放進Controllers
業務邏輯處理模塊, 將返回結果ret
改成文件讀寫後的內容, 並將該文件放置到Views
或者Template
模塊中, 就造成了最基礎版本的MVC
和MTV
框架接下來咱們使用Tornado
實現一個簡陋的任務表功能demo
web
commons.css
文件內容: 數據庫
.body {
margin: 0;
background-color: cornflowerblue;
}複製代碼
index.html
文件內容: flask
<!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>內容展現</h1>
<ul>
{% for item in contents %}
<li>{{item}}</li>
{% end %}
</ul>
</body>
</html>複製代碼
index.py
文件內容: 瀏覽器
#!/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 = []
爲存放的是輸入框輸入的內容settings
字典表示的是配置文件
'template_path': 'template'
模板文件的存放位置'static_path': 'static'
靜態文件的存放位置, 靜態文件必須聲明, 不然瀏覽器沒法找到靜態文件'static_url_prefix': 'static/'
靜態文件前綴, 減小每一個文件引入都要加前綴的麻煩application = tornado.web.Application([
(r"/index", MyHandle)
], **settings)複製代碼
根據瀏覽器的url肯定其對應的處理類並生成該類的對象application.listen(80)
設置服務端的監聽端口tornado.ioloop.IOLoop.instance().start()
阻塞服務端進程, 等待客戶端的訪問MyHandle
類中的get(self, *args, **kwargs)
方法, 服務端向客戶端返回index.html
文件index.html
文件以後, 在輸入框中輸入內容並提交以後會調用post(self, *args, **kwargs)
, 並將輸入的內容追加到self.get_argument('name')
獲取指定參數的內容CONTENTS_LIST
中, 服務端返回index.html
, 返回過程當中Toranado
CONTENTS_LIST
的內容渲染到index.html
以後纔會發給客戶端瀏覽器python中的模板引擎本質上是將html
文件轉換成一段python
函數字符串, 再經過compile
和exec
將該函數執行, 以此來進行模板渲染緩存
如今咱們介紹一下模板引擎的使用: cookie
uimethod.py
文件以下: session
#!/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>內容展現</h1>
<ul>
{% for item in contents %}
<li>{{item}}</li>
{% end %}
</ul>
<hr>
</body>
</html>複製代碼
咱們看看客戶端訪問的結果:
{{key}}
表示取key
對應的值, 當key
爲函數時候執行該函數並取該函數結果. 例如index.html
文件中的<h1>{{ag}}</h1>
實際上取得是index.py
的self.render("index.html", ag="this is ag", contents=CONTENTS_LIST)
中的參數ag
的值<h1>{{test_uimethod()}}</h1>
這裏執行的是自定義函數, 咱們將這個自定義函數寫在uimethod.py
文件中, 而且在index.py
文件中導入, 而後將index.py
文件中的settings
配置增長一行'ui_methods': ut
, 該行內容表示模板引擎可執行自定義函數{%%}
可用於循環語句和條件語言以及自定義類的執行, {% for item in contents %}
此處正是用於循環遍歷contents
中的內容<h1>{%module MyClass()%}</h1>
此處表示模板引擎執行自定義類, 該類的文件對應的是uimodule.py
文件, 咱們須要在index.py
的settings
中增長一行'ui_modules': ud
, 改行表示模板引擎可以使用自定義類index.html
文件引入css
的方式改成了<link rel="stylesheet" href='{{static_url("commons.css")}}'>
, static_url()
是模板引擎內置的自定義函數, 用該函數引入css
文件時候, 僅當css
文件內容發生變化時候, 瀏覽器纔會從新緩存該css
文件考慮到篇幅太長不容易閱讀, 筆者這裏將關於Tornado
框架的cookie
知識, 自定義session
的使用 路由系統,以及模板引擎高級部分放在後期文章分篇共享