python可以做很多事情,雖然它的強項在於進行向量運算和機器學習、深度學習等方面。但是在某些時候,我們仍然需要使用python對外提供web服務。
比如我們現在有一個用python寫好的模型演演算法,這個模型演演算法需要接收前端的輸入,然後進行模擬運算,最終得到最後的輸出。這個流程是一個典型的web服務,與其我們使用java或者nodejs來搭建一個web伺服器,不如我們就使用python自己的web框架來實現這一目標,減少技術棧的同時,還可以實現程式碼邏輯的統一,何樂而不為呢?
其實python的web框架也有很多種,比如django、flask等等。
這本系列的文章中,我們會介紹flask這個輕量級的web框架。
相信大家都用過不少web框架吧,從java的spring MVC,到nodejs的express和koa,有功能複雜的,也有功能簡單的。
但是不管他們的功能如何,其最重要最基本的一個功能就是能夠提供web服務,也就是說可以接收HTTP或者HTTPS的請求,然後返回對應的資料。這個功能通常包含的是核心的路由跳轉功能。
有了這個核心的功能,web框架基本上就可以正常執行了。配合上現在流行的前後端分離技術,一切水到渠成。
如果不想用前後端分離,那麼web框架還需要涉及到頁面的呈現技術。一般來說都會使用模板引擎作為前端頁面的呈現形式。
然後配合上對資料庫、快取、訊息佇列、靜態資源、紀錄檔、偵錯等附加的功能,一個完整的web框架就完成了。
flask雖然是一個輕量級web框架,但是該有的功能它全都有。
它的核心是提供了對web路由的支援,同時支援Jinja的模板語言。
flask是一個非常簡單優雅的web框架,flask需要Python 3.7及以上版本的支援。
為了區分python的不同開發環境,我們在使用flask的時候,可以使用python自帶的venv來建立不同的虛擬環境。venv跟conda的env很類似,都是用來建立虛擬環境,從而實現不同的環境進行分離的作用。
使用venv非常簡單,如果你用的開發工具是pycharm,那麼在建立python的flask專案的時候,會自動選擇對應的虛擬環境建立工具,這裡我們選擇使用venv即可自動建立。
當然你也可以使用下面的命令來手動建立venv:
$ mkdir learn-flask
$ cd learn-flask
$ python3 -m venv venv
建立好venv之後,使用下面的命令來啟用這個env:
. venv/bin/activate
venv安裝完畢之後,我們可以使用下面的命令安裝flask:
pip install Flask
安裝完畢之後,你可以在python專案site-packages裡面找到flask對應的依賴包:
可以看到裡面出了flask之外,還有其他的一些第三方依賴包,這些都是可以在後續的flask應用中使用到的。
flask的依賴包都安裝好之後,我們就可以寫一個最最簡單的web應用程式了,我們把這個應用程式命名為first.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def first():
return "<p>這是我的第一個flask程式!</p>"
if __name__ == '__main__':
app.run()
和普通的python程式不同的是,這裡我們先範例化了一個Flask物件,然後用類似註解的方式定義了一個route在fist這個方法上。
程式寫好了,如果你在pycharm IDE中,那麼可以右鍵執行,可以得到下面的內容:
FLASK_APP = first.py
FLASK_ENV = development
FLASK_DEBUG = 0
In folder /Users/data/git/ddean2009/learn-flask
/Users/data/git/ddean2009/learn-flask/venv/bin/python -m flask run
* Serving Flask app 'first.py'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
可以看到IDE為我們設定了幾個環境變數,分別是FLASK_APP:表示要執行的app名稱。FLASK_ENV:表示現在的執行環境是開發環境還是線上環境。FLASK_DEBUG表示是否是debug模式。
最終我們可以存取預設的http://127.0.0.1:5000,可以得到下面的內容:
說明整個程式執行成功了。
如果你想通過命令列來執行flask的應用,那麼可以用下面的命令:
flask --app first run
注意,這裡我們新增了--app這個引數來指定要執行的app名稱。如果不指定的話,flask會去尋找名叫app.py或者wsgi.py的檔案。如果你有這兩個檔案,那麼就可以直接使用flask run來執行了。
這裡的flask相當於python -m flask。
預設情況下flask的應用程式只能通過原生的瀏覽器來存取,如果你想通過遠端來存取的話,可以指定存取的host,如下所示:
flask run --host=0.0.0.0
到此,我們的一個基本的最簡單的flask web應用就完成了。
什麼?你還要了解更多?別急,下面我們再詳細介紹一些web應用程式所必須瞭解的知識。
路由也叫Routing,它是web應用程式中的靈魂,通過路由來定義各種URL和存取路徑。
在flask中,可以使用@app.route來對路由進行定義。@app.route類似於註解,可以放置在python的方法之上。
route中可以定義路由的名稱,路由的名稱可以跟方法的名稱不一樣:
@app.route('/test')
def test123():
return '我是一個測試'
路由的名稱還可以是動態的,可以取一個跟註解方法中引數的名稱一樣的引數名作為路由的引數用一個尖括號括起來,如下所示:
from markupsafe import escape
@app.route('/student/<name>')
def what_is_your_name(name):
return f'你的名字是: {escape(name)}'
這裡的方法體中我們呼叫了python的f函數來對字串進行格式化,在內部為了防止web輸入端的惡意注入,這裡參照了markupsafe的escape方法,可以對輸入的字串進行跳脫,從而避免了惡意的攻擊。
除了在路徑中指定引數之外,我們還可以自行指定引數的型別,在flask中路徑引數可以設定為下面的幾種型別:
型別 | 說明 |
---|---|
string |
預設型別,可以接收除了/之外的任何字串 |
int |
可以接收正整數 |
float |
可以接收正的浮點數 |
path |
和string類似,但是可以接收/ |
uuid |
接收uuid字串 |
比如我們想傳入一個路徑,那麼可以將其定義為path型別:
@app.route('/path/<path:subpath>')
def what_is_your_path(subpath):
return f'你的路徑是: {escape(subpath)}'
上面我們提到了string和path的區別,就在於path可以接收/,而string不能。
那麼在flask中/有什麼特殊的含義嗎?
我們知道/是用做路徑分割的,在flask中包含/和不包含/還是有一定的區別的。以下面的程式碼為例:
@app.route('/withslash/')
def with_slash():
return '這是帶slash的'
@app.route('/withoutslash')
def with_out_slash():
return '這是不帶slash的'
withslash的定義中帶了slash字尾,所以不管你存取/withslash
還是/withslash/
, 都會被跳轉到withslash/
。
但是因為withoutslash沒有帶slash,所以你只能存取/withoutslash
,但是不能存取/withoutslash/
,否則你可能得到一個404 「Not Found」錯誤。
預設情況下@app.route對外提供的是GET方法,如果你想對外提供一些不同的http方法,那麼可以在@app.route中使用methods:
@app.route('/diffMethod', methods=['GET', 'POST'])
def diff_method():
if request.method == 'POST':
return '這是post'
else:
return '這是get'
當然,你還可以使用@app.get或者@app.post把不同方法的請求分開:
@app.get('/getMethod')
def get_method():
return '這是get'
@app.post('/postMethod')
def post_method():
return '這是post'
web應用中少不了的是一些靜態資源,比如圖片,js或者css等。這些靜態資源可以看做是一種特殊的路由規則。在flask中,可以通過建立特殊的static目錄來達到這一目的。如下所示:
url_for('static', filename='style.css')
這裡面我們用到了url_for這個方法,這個方法實際上是用來構建對應方法的url的,可以舉下面的幾個例子來對url_for有個深入的瞭解。
urL_for的第一個引數是方法名,後面接的是url中定義的變數,如果url中並沒有這個變數,那麼將會以引數的形式附加在url的後面:
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/user/<username>')
def profile(username):
return f'{username}\'s profile'
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
輸出的內容如下:
/
/login
/login?next=/
/user/John%20Doe
如果我們只是用return來返回簡單的字串或者變數,那麼肯定滿足不了現代應用的需求了。
為了實現複雜的頁面功能,我們通常會使用模板。flask使用的是Jinja2這個模板語言。
怎麼使用模板呢?我們在返回的時候,可以使用render_template方法:
from flask import render_template
@app.route('/template/<name>')
def use_template(name=None):
return render_template('hello.html', name=name)
其中hello.html是模板檔案的名字,name是模板檔案中定義的變數。
以上就是flask的基本使用了,掌握到這些內容之後,相信大家已經可以使用flask做出一個簡單的web應用了。