1 什么是flask?
Flask 本是作者 Armin Ronacher在2010年4月1日的一個愚人節玩笑 ,不過后來大受歡迎,進而成為一個正式的python編寫的web框架
Flask是一個Python編寫的Web 微框架,讓我們可以使用Python語言快速實現一個網站或Web服務,在介紹Flask之前首先來聊下它和Django的聯系以及區別,django個大而全的web框架,它內置許多模塊,flask是一個小而精的輕量級框架,Django功能大而全,Flask只包含基本的配置, Django的一站式解決的思路,能讓開發者不用在開發之前就在選擇應用的基礎設施上花費大量時間。Django有模板,表單,路由,基本的數據庫管理等等內建功能。與之相反,Flask只是一個內核,默認依賴於2個外部庫: Jinja2 模板引擎和 WSGI工具集--Werkzeug , flask的使用特點是基本所有的工具使用都依賴於導入的形式去擴展,flask只保留了web開發的核心功能。
WSGI(web服務器網關接口)是python中用來規定web服務器如何與python Web服務器如何與Python Web程序進行溝通的標准,本質上就是一個socket服務端。而 Werkzeug模塊 就是WSGI一個具體的實現
關鍵詞:一個Python編寫微web框架 一個核心兩個庫( Jinja2 模板引擎 和 WSGI工具集)
2 為什么要有flask?
flask性能上基本滿足一般web開發的需求, 並且靈活性以及可擴展性上要優於其他web框架, 對各種數據庫的契合度都非常高
關鍵詞:1. 性能基本滿足需求 2 .靈活性可拓展性強 3. 對各種數據庫的契合度都比較高。
4.在真實的生產環境下,小項目開發快,大項目設計靈活
3 學前准備:虛擬環境
3.1 虛擬環境是什么?
虛擬環境是隔離的Python解釋器環境。通過創建虛擬環境,你可以擁有一個獨立的Python解釋器環境,相當於對全局的python解釋器環境拷貝一份私有的副本, 這樣做的好處是可以為每一個項目創建獨立的Python解釋器環境,因為不同的項目常常會依賴不同版本的庫或Python版本。使用虛擬環境可以保持全局Python解釋器環境的干凈,避免包和版本的混亂,並且可以方便地區分和記錄每個項目的依賴,所謂環境追根溯源也是文件,既然是文件就支持拷貝到各個平台上,所以同時提高了可移植性,以便在新環境下復現依賴環境。
舉例說明:
例1:如果你同時有很多個項目,有一個爬蟲項目,有一個Flask項目,有一個Django項目放在一個環境下,那么管理相關的第三方庫難免混亂。
例2:如果你有兩個Flask項目,但是兩個項目flask版本不一致,會出現版本沖突問題
關鍵詞:1、Python解釋器的一個私有副本 2、解決了包管理混亂、版本沖突、提高了移植性
3.2 如何使用虛擬環境?
3.2.1 搭建虛擬環境
windows的開發環境的安裝過程,我們使用的是virtualenv虛擬開發環境,首先安裝相關包的依賴
pip install virtualenvwrapper-win
利用安裝好的模塊我們創建一個虛擬環境
##注意:這個‘’first_01_env‘’ 是我們自己給虛擬環境取的名字,並且要記錄一下圖(1)的安裝路徑,一會我們需要使用。
mkvirtualenv first_01_env
虛擬環境其他相關命令:
01、切換到指定的虛擬環境:注意我們進入虛擬環境是需要用workon命令,但是首次安裝成功會自動進入虛擬環境。
workon first_01_env
02、退出虛擬環境
deactivate
03、刪除指定的虛擬環境
rmvirtaulenv first_01_env
04、列出所有虛擬環境:
lsvirtualenv
05、進入到虛擬環境所在的目錄:
cdvirtualenv
3.2.1 在虛擬環境中安裝我們的Flask模塊
pip install flask
Collecting flask
...
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0
從上面成功安裝的輸出內容可以看出,除了Flask包外,同時被安裝的還有5個依賴包,它們的主要介紹如表(1-1)所示。
包名及版本 | 功能 |
---|---|
Jinja2-2.10 | 渲染模板引擎工具集 |
MarkupSafe-1.1.0 | 可以識別HTML轉義規則。HTML字符轉義工具集 |
Werkzeug-0.14.1 | Web 框架的底層庫,提供了請求及響應以及開發服務器的功能,簡稱WSGI工具集 |
click-7.0 | 命令行工具集 |
itsdangerous-1.1.0 | 加密工具集 |
表(1-1)
首先對這5個庫先有一個印象,接下來會在具體的實際應用中應用這些庫。
✔提示:這些庫均由Flask團隊開發
4 開始我們的第一個Flask程序
這里我們使用pycharm編輯器來學習Flask,pycharm的安裝我們就不重復了。
4.1 創建一個Flask程序
具體操作如圖(a)--圖(d)
第一步
圖(a)
第二步
圖(b)
第三步
!注意 如果找不到虛擬環境路徑可以參考虛擬環境其他命令
lsvirtualenv # 列出所有的虛擬環境
workon first_01_env # 切換到指定的虛擬環境
cdvirtualenv # 切換到指定的虛擬環境路徑 該目錄就是我們所要的路徑
圖(c)
第四步
圖(d)
4.2 解讀Flask程序
4.2.1 項目目錄詳解:
“static文件夾”用於存放各種靜態文件 css、js、圖片等等
“templates文件夾”用於存放html模板文件
“app.py”為我們的主文件 ,啟動項目需要啟動該文件
注意 app.py 文件的名字我們可以自由命名,但是除了flask.py 這種和Flask庫相沖突的名字
主文件app.py文件代碼
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
4.2.2 代碼拆分為三部分 :
第一部分
from flask import Flask
app = Flask(__name__)
導入我們安裝好的flask包,通過flask包導入Flask類,Flask類即為Flask的核心,實例化這個Flask類的到一個實例化對象app。
__name__
這個特殊的參數:Python會根據所處的模塊來賦予__name__
變量相應的值,對於我們的程序來說(app.py),這個值為app。
@app.route('/')
def hello_world():
return 'Hello World!'
如果有過對其他web框架的了解,相信看見這個已經看出了一些門道。沒錯這個 @app.route('/')
就是用來匹配url的,在我們的flask里面是以裝飾器來實現的,裝飾器引用的也是我們上面實例化核心類出來的對象。
那么如果路由下面跟的函數什么呢 ?沒錯就是我們的視圖函數,如果匹配到了路由就會觸發我們的視圖函數執行,並且return回具體的數據給前端或者移動端。
不是很理解沒關系,我們先大概有個印象,會在接下來的章節詳細講解路由以及視圖函數的使用
第三部分
if __name__ == '__main__':
app.run()
先不管邏輯判斷,先看 app.run()
, app.run()
源碼如下去閱讀源碼不難發現,在內部定義了默認的 ip+端口為127.0.0.1:5000,並且調用了werkzeug.serving為我們創建了一個開發服務器(由依賴包Werkzeug提供),對套接字有一定了解的朋友,其內部就是做了一個循環監聽的功能以便交互.
關鍵詞:app.run()
實現了flask
程序在開發環境下運行起來,並且默認ip和端口是127.0.0.1:5000
。
def run(self, host=None, port=None, debug=None,
load_dotenv=True, **options):
...
_host ='127.0.0.1'
_port = 5000
...
host = host or sn_host or _host
port = int(port or sn_port or _port)
...
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
finally:
# reset the first request information if the development server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False
在第三部分中還有一個if
判斷,那么這個判斷的作用是什么呢,有python基礎的朋友對這個寫法大概不陌生,if
邏輯判斷時只有本文件為執行文件的時候才會執行,為什么要這么設計呢?因為在開發環境我們是以app.py作為執行文件,但是在真實的生產環境下 ,此文件會作為被調用的文件,並且真實的生成環境不會用到app.run()做監聽分配
, 原因是性能太低了,
關鍵詞:保證了app.run()只用於開發環境,並且不影響真實的生產環境。
三部分串講
導入Flask的核心類實例化對象app,然后app作為裝飾器使用匹配url分發給下面的視圖函數,然后執行該頁面會觸發app調用run()方法運行起來整個項目。
4.2.2.1 Werkzeug簡介
Werkzeug是一個WSGI工具包,他可以作為一個Web框架的底層庫。這里稍微說一下, werkzeug 不是一個web服務器,也不是一個web框架,而是一個工具包,官方的介紹說是一個 WSGI 工具包,它可以作為一個 Web 框架的底層庫,因為它封裝好了很多 Web 框架的東西,例如 Request,Response 等等 。
代碼示例:
from werkzeug.wrappers import Request, Response
@Request.application
def hello(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, hello)
了解
看到了這個wekzeug是不是特別像我們的flask代碼,沒錯我們的flask正是依賴於這個werkzeug模塊,由wekzeug模塊實現了socket服務端的功能,hello必然是加括號運行了,才會執行hello里面的代碼,而在我們的flask中app.run()會調用run_simple(host, port, self, **options)
把上面代碼例子的hello替換成了self也就是app。app()會觸發Flask類的__call__
方法。
所以所flask程序的入口就在__call__
方法中,而__call__
方法返回self.wsgi_app(environ, start_response)
,所以整個程序的執行過程都在 self.wsgi_app(environ, start_response)
中.
小節:
1 app.run() 調用 werkzeug.serving的run_simple(host, port, self, **options)
2 self()等價於app(), app()調用Flask類的__call__方法
3 Flask類的__call__方法返回了 self.wsgi_app(environ, start_response)
4 flask程序的執行過程都在 self.wsgi_app(environ, start_response)中
具體代碼:
def run(self, host=None, port=None, debug=None,
load_dotenv=True, **options):
...
_host ='127.0.0.1'
_port = 5000
...
host = host or sn_host or _host
port = int(port or sn_port or _port)
...
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
finally:
# reset the first request information if the development server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False
...
def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)
...
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
...
關鍵詞:
- Werkzeug是一個WSGI工具包,本質上是一個socket服務端。
- flask基於Werkzeug,flask只保留了web開發的核心功能。
- flask的執行過程都在
def wsgi_app(self, environ, start_response):
中
4.2.3 運行項目
運行起來我們的flask項目,見圖(2),也可以在app.py直接右鍵run啟動項目
圖(2)
然后訪問http://127.0.0.1:5000/可以見圖(3)
圖(3)
!強調以后我們創建flask項目不要用pycharm自帶的flask快捷方式創建,上邊的快捷創建方式是便於講解和理解,真實的生產環境更推薦直接創建一個空的python項目
4.2.4 詳解DEBUG模式
4.3.4.1 DEBUG模式解決了兩個問題。
-
flask代碼中如果出現了異常,我們在瀏覽器中不會提示具體的錯誤信息,開啟debug模式后會把具體的錯誤信息發送到瀏覽器上。
-
flask代碼如果被修改了,必須要重啟項目修改的代碼才會有效,開啟debug模式后我們修改了代碼只要
ctrl+s
我們的flask項目就會自動重新加載,不需要手動加載整個網站。例1:
此案例明顯出現了一個數組越界的問題
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): a = [1,2,3,4] print(a[4]) return "hello" if __name__ == '__main__': app.run()
訪問如圖(4)
圖(4)
如圖4只提示了服務器內部錯誤,並沒有提示具體的錯誤原因
好我們為app.run()添加參數改寫為app.run(debug=True)
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
a = [1,2,3,4]
print(a[4])
return "hello"
if __name__ == '__main__':
app.run(debug=True)
再次訪問如圖(5)
圖(5)
我們看到了具體的報錯信息 IndexError: list index out of range
並且每次修改代碼的時候按下ctrl+s
保存一下都會自動重新加載flask項目代碼,在此就不做演示了
!強調不要用快捷創建falsk的方式創建項目,就像創建一個普通的python項目一樣,或者打開一個空的文件的方式創建,否則debug=True會無效
4.2.4.2 四種開啟DEBUG的方式
第一種
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
a = [1,2,3,4]
print(a[4])
return "hello"
if __name__ == '__main__':
app.run(debug=True) # 設置
第二種
from flask import Flask
app = Flask(__name__)
app.debug = True # 設置
@app.route('/')
def hello():
a = [1,2,3,4]
print(a[4])
return "hello"
if __name__ == '__main__':
app.run()
第三種
from flask import Flask
app = Flask(__name__)
app.config.update(DEBUG=True) # 設置
@app.route('/')
def hello():
a = [1,2,3,4]
print(a[4])
return "hello"
if __name__ == '__main__':
app.run()
第四種
需要在app.py
所在的目錄里 再創建一個config.py
,隨着我們的學習會越來越多的用到這個配置文件,來配置我們的flask
項目,注意配置的信息一般為大寫。
config.py
DEBUG = True
app.py
from flask import Flask
import config # 導入
app = Flask(__name__)
app.config.from_object(config) # 設置
@app.route('/')
def hello():
a = [1,2,3,4]
print(a[4])
return "hello"
if __name__ == '__main__':
app.run()
app.config 本質上繼承的字典,是字典的子類的一個對象 如圖(6)
圖(6)
4.2.4.3 DEBUG的PIN碼可以在瀏覽器端調試代碼使用(不推薦使用,了解就可以)
* Debugger PIN: 648-906-962
圖(7)
可以支持在網頁端調試
圖(8)