【Python之路】特別篇--Bottle

Bottle

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

Bottle框架大體能夠分爲如下部分:python

  • 路由系統,將不一樣請求交由指定函數處理瀏覽器

  • 模板系統,將模板中的特殊語法渲染成字符串,值得一說的是Bottle的模板引擎能夠任意指定:Bottle內置模板、makojinja2cheetahcookie

  • 公共組件,用於提供處理請求相關的信息,如:表單數據、cookies、請求頭等app

  • 服務,Bottle默認支持多種基於WSGI的服務框架

框架的基本使用:socket

#!/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)

1、路由系統async

路由系統是的url對應指定函數,當用戶請求某個url時,就由指定函數處理當前請求,對於Bottle的路由系統能夠分爲一下幾類:ide

  • 靜態路由函數

  • 動態路由

  • 請求方法路由

  • 二級路由

1.靜態路由

@root.route('/hello/')
def index():
    return template('<b>Hello {{name}}</b>!', name="Alex")

2.動態路由

@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):
    return static_file(path, root='static')

3.請求方法路由

@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
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bottle import template, Bottle
from bottle import static_file
root = Bottle()
 
@root.route('/hello/')
def index():
    return template('<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)

2、模板系統

模板系統用於將Html和自定的值二者進行渲染,從而獲得字符串,而後將該字符串返回給客戶端。

咱們知道在Bottle中可使用 內置模板系統、makojinja2cheetah等,之內置模板系統爲例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>{{name}}</h1>
</body>
</html>
html文件
#!/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 中
    return template('xx.html', name='alex')
 
root.run(host='localhost', port=8080)

一、語法

  • 單值

  • 單行Python代碼

  • Python代碼快

  • Python、Html混合

<h1>一、單值</h1>
{{name}}
 
<h1>二、單行Python代碼</h1>
% s1 = "hello"
 
<h1>三、Python代碼塊</h1>
<%
    # A block of python code
    name = name.title().strip()
    if name == "Alex":
        name="seven"
%>
 
<h1>四、Python、Html混合</h1>
 
% if True:
    <span>{{name}}</span>
% end
<ul>
  % for item in name:
    <li>{{item}}</li>
  % end
</ul>

二、函數 

include(sub_template, **variables)

# 導入其餘模板文件
 
% 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.html
# 導入母版
 
% rebase('base.html', title='Page Title')
<p>Page Content ...</p>

defined(name)

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

get(name, default=None)

# 獲取某個變量的值,不存在時可設置默認值

setdefault(name, default)

# 若是變量不存在時,爲變量設置默認值

擴展:自定義函數

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

</body>
</html>
hello.html
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', hello=custom)

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

注:變量或函數前添加 【 ! 】,則會關閉轉義的功能

3、公共組件

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

【接收用戶請求】

當框架接收到用戶請求以後,將請求信息封裝在Bottle的request中,以供開發人員使用

【響應相關內容】

當開發人員的代碼處理完用戶請求以後,會將其執行內容相應給用戶,相應的內容會封裝在Bottle的response中,而後再由框架將內容返回給用戶

因此,公共組件本質其實就是爲開發人員提供接口,使其可以獲取用戶信息並配置響應內容。

一、request

Bottle中的request實際上是一個LocalReqeust對象,其中封裝了用戶請求的相關信息:

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
    環境相關相關

二、response

Bottle中的response實際上是一個LocalResponse對象,其中框架即將返回給用戶的相關信息:

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'
上傳文件

4、服務

對於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方法時指定參數便可:

#!/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,若是想要使用其餘時,則須要首先安裝相關類庫,而後才能使用。如:

# 若是使用Tornado的服務,則須要首先安裝tornado才能使用

class TornadoServer(ServerAdapter):
    """ The super hyped asynchronous server by facebook. Untested. """
    def run(self, handler): # pragma: no cover
        # 導入Tornado相關模塊
        import tornado.wsgi, tornado.httpserver, tornado.ioloop
        container = tornado.wsgi.WSGIContainer(handler)
        server = tornado.httpserver.HTTPServer(container)
        server.listen(port=self.port,address=self.host)
        tornado.ioloop.IOLoop.instance().start()

PS:以上WSGI中提供了19種,若是想要使期支持其餘服務,則須要擴展Bottle源碼來自定義一個ServerAdapter

更多參見:http://www.bottlepy.org/docs/dev/index.html

相關文章
相關標籤/搜索