1. 程式人生 > >Python之路【第十八篇】:Web框架們

Python之路【第十八篇】:Web框架們



Python的WEB框架

Bottle

Bottle是一個快速、簡潔、輕量級的基於WSIG的微型Web框架,此框架只由一個 .py 檔案,除了Python的標準庫外,其不依賴任何其他模組。

?
1 2 3 4 pip install bottle easy_install bottle apt-get install python-bottle wget http://bottlepy.org/bottle.py

Bottle框架大致可以分為以下部分:

  • 路由系統,將不同請求交由指定函式處理
  • 模板系統,將模板中的特殊語法渲染成字串,值得一說的是Bottle的模板引擎可以任意指定:Bottle內建模板、
    mako
    jinja2cheetah
  • 公共元件,用於提供處理請求相關的資訊,如:表單資料、cookies、請求頭等
  • 服務,Bottle預設支援多種基於WSGI的服務,如:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 server_names = { 'cgi': CGIServer, 'flup': FlupFCGIServer, 'wsgiref': WSGIRefServer, 'waitress': WaitressServer, 'cherrypy'
    : CherryPyServer, 'paste': PasteServer, 'fapws3': FapwsServer, 'tornado': TornadoServer, 'gae': AppEngineServer, 'twisted': TwistedServer, 'diesel': DieselServer, 'meinheld': MeinheldServer, 'gunicorn': GunicornServer, 'eventlet': EventletServer, 'gevent': GeventServer, 'geventSocketIO':GeventSocketIOServer,
    'rocket': RocketServer, 'bjoern': BjoernServer, 'auto': AutoServer, }

框架的基本使用

?
1 2 3 4 5 6 7 8 9 10 11 #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle root =Bottle() @root.route('/hello/') def index(): return"Hello World" # return template('<b>Hello {{name}}</b>!', name="Alex") root.run(host='localhost', port=8080)

一、路由系統

路由系統是的url對應指定函式,當用戶請求某個url時,就由指定函式處理當前請求,對於Bottle的路由系統可以分為一下幾類:

  • 靜態路由
  • 動態路由
  • 請求方法路由
  • 二級路由

1、靜態路由

?
1 2 3 @root.route('/hello/') def index(): returntemplate('<b>Hello {{name}}</b>!', name="Alex")

2、動態路由

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @root.route('/wiki/<pagename>') def callback(pagename): ... @root.route('/object/<id:int>') def callback(id): ... @root.route('/show/<name:re:[a-z]+>') def callback(name): ... @root.route('/static/<path:path>') def callback(path): returnstatic_file(path, root='static')

3、請求方法路由

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @root.route('/hello/', method='POST') def index(): ... @root.get('/hello/') def index(): ... @root.post('/hello/') def index(): ... @root.put('/hello/') def index(): ... @root.delete('/hello/') def index(): ...

4、二級路由

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle

app01 = Bottle()

@app01.route('/hello/', method='GET')
def index():
    return template('<b>App01</b>!')
app01.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle

app02 = Bottle()


@app02.route('/hello/', method='GET')
def index():
    return template('<b>App02</b>!')
app02.py ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle from bottle import static_file root =Bottle() @root.route('/hello/') def index(): returntemplate('<b>Root {{name}}</b>!', name="Alex") from framwork_bottle import app01 from framwork_bottle import app02 root.mount('app01', app01.app01) root.mount('app02', app02.app02) root.run(host='localhost', port=8080)

二、模板系統

模板系統用於將Html和自定的值兩者進行渲染,從而得到字串,然後將該字串返回給客戶端。我們知道在Bottle中可以使用 內建模板系統、makojinja2cheetah等,以內建模板系統為例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>{{name}}</h1>
</body>
</html>
hello_template.tpl ?
1 2 3 4 5 6 7 8 9 10 11 12 #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle root =Bottle() @root.route('/hello/') def index(): # 預設情況下去目錄:['./', './views/']中尋找模板檔案 hello_template.html # 配置在 bottle.TEMPLATE_PATH 中 returntemplate('hello_template.tpl', name='alex') root.run(host='localhost', port=8080)

1、語法

  • 單值
  • 單行Python程式碼
  • Python程式碼快
  • Python、Html混合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <h1>1、單值</h1> {{name}} <h1>2、單行Python程式碼</h1> % s1 = "hello" <h1>3、Python程式碼塊</h1> <% # A block of python code name= name.title().strip() ifname =="Alex": name="seven" %> <h1>4、Python、Html混合</h1> % if True: <span>{{name}}</span> % end <ul> %for item inname: <li>{{item}}</li> %end </ul>

2、函式 

include(sub_template, **variables)

?
1 2 3 4 5 # 匯入其他模板檔案 % include('header.tpl', title='Page Title') Page Content % include('footer.tpl')

rebase(name, **variables)

<html>
<head>
  <title>{{title or 'No title'}}</title>
</head>
<body>
  {{!base}}
</body>
</html>
base.tpl ?
1 2 3 4 # 匯入母版 % rebase('base.tpl', title='Page Title') <p>Page Content ...</p>

defined(name)

?
1 # 檢查當前變數是否已經被定義,已定義True,未定義False

get(name, default=None)

?
1 # 獲取某個變數的值,不存在時可設定預設值

setdefault(name, default)

?
1 # 如果變數不存在時,為變數設定預設值

擴充套件:自定義函式

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>自定義函式</h1>
    {{ wupeiqi() }}

</body>
</html>
hello_template.tpl
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle,SimpleTemplate
root = Bottle()


def custom():
    return '123123'


@root.route('/hello/')
def index():
    # 預設情況下去目錄:['./', './views/']中尋找模板檔案 hello_template.html
    # 配置在 bottle.TEMPLATE_PATH 中
    return template('hello_template.html', name='alex', wupeiqi=custom)

root.run(host='localhost', port=8080)
main.py

注:變數或函式前新增 【 ! 】,則會關閉轉義的功能

三、公共元件

由於Web框架就是用來【接收使用者請求】-> 【處理使用者請求】-> 【響應相關內容】,對於具體如何處理使用者請求,開發人員根據使用者請求來進行處理,而對於接收使用者請求和相應相關的內容均交給框架本身來處理,其處理完成之後將產出交給開發人員和使用者。

【接收使用者請求】

當框架接收到使用者請求之後,將請求資訊封裝在Bottle的request中,以供開發人員使用

【響應相關內容】

當開發人員的程式碼處理完使用者請求之後,會將其執行內容相應給使用者,相應的內容會封裝在Bottle的response中,然後再由框架將內容返回給使用者

所以,公共元件本質其實就是為開發人員提供介面,使其能夠獲取使用者資訊並配置響應內容。

1、request

Bottle中的request其實是一個LocalReqeust物件,其中封裝了使用者請求的相關資訊:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 request.headers 請求頭資訊 request.query get請求資訊 request.forms post請求資訊 request.files 上傳檔案資訊 request.params get和post請求資訊 request.GET get請求資訊 request.POST post和上傳資訊 request.cookies cookie資訊 request.environ 環境相關相關

2、response

Bottle中的request其實是一個LocalResponse物件,其中框架即將返回給使用者的相關資訊:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 response response.status_line 狀態行 response.status_code 狀態碼 response.headers 響應頭 response.charset 編碼 response.set_cookie 在瀏覽器上設定cookie response.delete_cookie 在瀏覽器上刪除cookie

例項:

from bottle import route, request

@route('/login')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@route('/login', method='POST')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if check_login(username, password):
        return "<p>Your login information was correct.</p>"
    else:
        return "<p>Login failed.</p>"
基本Form請求
<form action="/upload" method="post" enctype="multipart/form-data">
  Category:      <input type="text" name="category" />
  Select a file: <input type="file" name="upload" />
  <input type="submit" value="Start upload" />
</form>


@route('/upload', method='POST')
def do_upload():
    category   = request.forms.get('category')
    upload     = request.files.get('upload')
    name, ext = os.path.splitext(upload.filename)
    if ext not in ('.png','.jpg','.jpeg'):
        return 'File extension not allowed.'

    save_path = get_save_path_for_category(category)
    upload.save(save_path) # appends upload.filename automatically
    return 'OK'
上傳檔案 

四、服務

對於Bottle框架其本身未實現類似於Tornado自己基於socket實現Web服務,所以必須依賴WSGI,預設Bottle已經實現並且支援的WSGI有:

server_names = {
    'cgi': CGIServer,
    'flup': FlupFCGIServer,
    'wsgiref': WSGIRefServer,
    'waitress': WaitressServer,
    'cherrypy': CherryPyServer,
    'paste': PasteServer,
    'fapws3': FapwsServer,
    'tornado': TornadoServer,
    'gae': AppEngineServer,
    'twisted': TwistedServer,
    'diesel': DieselServer,
    'meinheld': MeinheldServer,
    'gunicorn': GunicornServer,
    'eventlet': EventletServer,
    'gevent': GeventServer,
    'geventSocketIO':GeventSocketIOServer,
    'rocket': RocketServer,
    'bjoern' : BjoernServer,
    'auto': AutoServer,
}
WSGI

使用時,只需在主app執行run方法時指定引數即可:

?
1 2 3 4 5 6 7 8 9 10 #!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import Bottle root =Bottle() @root.route('/hello/') def index(): return"Hello World" # 預設server ='wsgiref' root.run(host='localhost', port=8080, server='wsgiref')

預設server="wsgiref",即:使用Python內建模組wsgiref,如果想要使用其他時,則需要首先安裝相關類庫,然後才能使用。如:

# 如果使用To