flask和django本質是同樣的,都是web框架。html
可是django自帶了一些組件,flask雖然自帶的組件比較少,可是它有不少的第三方插件。
mysql
那麼在什麼狀況下,使用flask呢?web
好比讓flask寫一個大型項目,它須要不少第三方插件。
那麼堆着堆着,就和django同樣了!面試
總結:sql
若是一個項目須要的插件比較少,可使用flask。
若是須要的插件比較多,使用django更加方便。數據庫
在flask中,裝飾器用的是比較多的。看下面一段代碼django
from flask import Flask app = Flask(__name__) @app.route('/index') def index(): return 'index' if __name__ == '__main__': app.run()
如今有一個裝飾器函數xxx,若是須要在每次請求index頁面時,作一些操做。json
那麼裝飾器,應該加在哪裏呢?flask
這樣?瀏覽器
@xxx @app.route('/index')
仍是這樣呢?
@app.route('/index') @xxx
答案是,必須在@app.route('/index')下面才行。爲何呢?
由於若是加在@app.route上面,那麼執行@xxx以後,那麼就直接走視圖函數了。已經沒有意義了!
而若是在@app.route下面,那麼執行到路由後,就會先執行@xxx,再執行視圖函數!
看下面一段代碼,index視圖函數,加了一個裝飾器xxxx
from flask import Flask app = Flask(__name__) def xxxx(func): def inner(*args,**kwargs): print('before') return func(*args,**kwargs) return inner @app.route('/index') @xxxx def index(): return 'index' if __name__ == '__main__': app.run()
啓動程序,訪問首頁
http://127.0.0.1:5000/index
查看Pycharm控制檯輸出: before
若是再加視圖函數home,並應用xxxx裝飾器
from flask import Flask app = Flask(__name__) def xxxx(func): def inner(*args,**kwargs): print('before') return func(*args,**kwargs) return inner @app.route('/index') @xxxx def index(): return 'index' @app.route('/home') @xxxx def home(): return 'home' if __name__ == '__main__': app.run()
啓動以後,會直接報錯
AssertionError: View function mapping is overwriting an existing endpoint function: inner
爲何呢?因爲代碼是從上至下執行的。視圖函數執行xxxx裝飾器以後,使用__name__方法獲取函數名時,名字是inner
那麼所以執行到home時,函數名也是inner。那麼flask就會拋出異常,inner函數重複了!
如何解決呢?使用functools就能夠了!它會保留原函數信息,包括函數名!
from flask import Flask import functools app = Flask(__name__) def xxxx(func): @functools.wraps(func) def inner(*args,**kwargs): print('before') return func(*args,**kwargs) return inner @app.route('/index') @xxxx def index(): return 'index' @app.route('/home') @xxxx def home(): return 'home' if __name__ == '__main__': app.run()
再次執行,就不會報錯了。
所以,之後爲了裝飾器不出問題,必定要加functools
看下面的代碼,b1和b2誰會先執行?
# import pymysql # from DBUtils.PooledDB import PooledDB, SharedDBConnection # POOL = PooledDB( # creator=pymysql, # 使用連接數據庫的模塊 # maxconnections=6, # 鏈接池容許的最大鏈接數,0和None表示不限制鏈接數 # mincached=2, # 初始化時,連接池中至少建立的空閒的連接,0表示不建立 # maxcached=5, # 連接池中最多閒置的連接,0和None不限制 # maxshared=3, # 連接池中最多共享的連接數量,0和None表示所有共享。PS: 無用,由於pymysql和MySQLdb等模塊的 threadsafety都爲1,全部值不管設置爲多少,_maxcached永遠爲0,因此永遠是全部連接都共享。 # blocking=True, # 鏈接池中若是沒有可用鏈接後,是否阻塞等待。True,等待;False,不等待而後報錯 # maxusage=None, # 一個連接最多被重複使用的次數,None表示無限制 # setsession=[], # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."] # ping=0, # # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always # host='127.0.0.1', # port=3306, # user='root', # password='123', # database='pooldb', # charset='utf8' # ) ''' 1.Flask路由 1.endpoint="user" # 反向url地址 2.url_address = url_for("user") 3.methods = ["GET","POST"] # 容許請求進入視圖函數的方式 4.redirect_to # 在進入視圖函數以前重定向 5./index/<nid> # 動態參數路由 <int:nid> def index(nid) 6.strict_slashes # 是否嚴格要求路由地址 / 7.defaults={"nid":1} # def index(nid) 2.Flask初始化配置(實例化): 1.template_folder # 指定模板路徑 2.static_url_path # 指定靜態文件目錄的URL地址 3.static_folder # 指定靜態文件目錄路徑 3.Flask對象配置 1.DEBUG #開發模式的調試功能 True False 2.app.config.from_object(class) # 經過對象的方式導入配置 3.secret_key # 開啓session功能的時候須要添加的配置 4.Blueprint 1.將功能和主程序分離,註冊 2.bl = Blueprint("dongdong",__name__) 3.註冊 register_blueprint(bl) 5.send_file jsonify 1.send_file # 打開並返回文件 content-type:文件類型 2.jsonify # 將一個字符串 轉爲JSON格式 加入 content-type:application/json 頭 6.特殊的裝飾器: 1.before_request # 在請求進入視圖函數以前執行的函數(登陸認證) 2.after_request # 在請求響應回瀏覽器以前執行的函數 3.before_first_request # 在第一次請求進入視圖函數以前執行的函數 4.errorheader(404) # 當遇到此類錯誤響應的時候(自定義錯誤頁面) 7.flash 1.flash("msg","tag") # 閃現存儲 2.get_flashed_messages(category_filter=["tag"]) # 閃現取值 只要用到了get_flashed_messages就必定清空flash 1.DButils 數據庫鏈接池 建立鏈接池同時建立鏈接 用到鏈接時從鏈接池中抽取一個鏈接 釋放鏈接時將鏈接放回鏈接池中 節省與mysql的通信次數和時長 2.Websocket 通信協議 Web + socket QQ 即時通信軟件 97 初期輪詢: QQ 聯衆 軟件不斷的循環訪問服務器問它有沒有給我發送的消息 優勢:響應及時 缺點:浪費CPU資源,浪費帶寬 長輪詢: 當客戶端發起詢問,服務器說你等着1分鐘以後,你再來問我 斷開再次發起鏈接,服務器幫你輪詢 優勢:響應及時 缺點:用戶一旦造成規模,服務器消耗是致命的 新的協議 websocket 規定了一個數據格式 收發數據 該收就收 該發就發 3.羣聊 4.私聊 ''' # from flask import Flask,request,redirect,session # # app = Flask(__name__) # app.secret_key = "DragonFire" # # # @app.before_request # def is_login(): # 判斷是否登陸 # # 白名單設置,判斷爲登陸頁面時 # if request.path == "/login": # # 跳過處理 # return None # # 判斷session是不存在時 # if not session.get("user"): # # 重定向到登陸頁面 # return redirect("/login") # # @app.after_request # def foot_log(environ): # 記錄訪問日誌 # print(environ) # 響應信息 # # 判斷請求路徑不是登陸頁面 # if request.path != "/login": # # 打印訪問路徑 # print("有客人訪問了",request.path) # # return environ # # @app.route("/login",methods=["POST","GET"]) # def login(): # if request.method == "GET": # return "Login" # # user = request.form["username"] # form表單獲取 # pwd = request.form["password"] # form表單獲取 # # 判斷form表示數據和 後臺數據庫匹配 # # models.UserInfo.objects.filter(username=user,password=pwd).first() # if user == 'xiao' and pwd == '123': # # 設置session # session["user"] = user # # 跳轉首頁 # return redirect("/index") # # # @app.route("/index") # def index(): # return "Index" # # @app.route("/home") # def home(): # return "Home" # # if __name__ == '__main__': # app.run("0.0.0.0", 5000) ''' 1.玩具開機提示語 剛剛開機的時候: 1.受權問題(MD5受權碼)提示語 : 請聯繫玩具廠商 2.綁定問題 提示語 : 快給我找一個小主人 3.成功 提示語:歡迎使用 2.爲多個玩具發送點播: mpop 彈出菜單 3.聊天界面: <div class="leftd"> <img src="avatar/girl.jpg" class="leftd_h" /> <div class="speech left">點擊播放</div> </div> <div class="rightd"> <img src="avatar/girl.jpg" class="rightd_h" /> <div class="speech right">點擊播放</div> </div> 按住錄音: hold: 按住事件 開始錄音(回調函數) release: 鬆開事件 結束錄音 執行錄音中的回調函數 4.app錄音: var rec = plus.audio.getRcorder() rec.record( {filename:"_doc/audio/",format:"amr"}, function(success){ success //錄音文件保存路徑 }, function(error){} ) rec.stop() 5.app與服務器端文件傳輸(ws傳輸): 1.app使用dataURL方式打開錄音文件 : base64 文件 2.經過某個函數 將 Base64 格式的文件 轉爲 Blob 用於 websocket傳輸 3.將Blob對象使用Ws發送至服務端 4.服務端保存文件(amr) 5.將amr 轉換爲 mp3 使用 ffmpeg -i xxx.amr xxx.mp3 6.簡單的對話(app向玩具(web)發起): app: 1.發起兩次 ws.send({to_user:}) 告訴服務端我要發給誰消息 2. ws.send(blob) app與服務器端文件傳輸 websocket服務: 0.建立兩個變量,用於接收to_user 和 blob對象 1.收到用戶的JSON字符串,to_user 獲取對方的Websocket,用戶send 2.收到用戶的Blob對象,語音文件 保存成amr文件,轉換成mp3 注意保存文件的路徑 3.將轉換完成的文件發送給 to_user 4.兩個變量置空 ''' from flask import Flask import functools app = Flask(__name__) @app.before_request def b1(): print('b1') @app.before_request def b2(): print('b2') def xxxx(func): @functools.wraps(func) def inner(*args,**kwargs): print('before') return func(*args,**kwargs) return inner @app.route('/index') @xxxx def index(): return 'index' @app.route('/home') @xxxx def home(): return 'home' if __name__ == '__main__': app.run(debug=True)
啓動程序,訪問index頁面
http://127.0.0.1:5000/index
查看Pycharm控制檯輸出:
b1
b2
before
能夠發現,b1先執行。爲何呢?由於代碼是從上至下執行的,因此誰先加載,誰就先執行!
關於before_request源碼分析,請參考連接:
https://blog.csdn.net/slamx/article/details/50491192
舉例:
from flask import Flask app = Flask(__name__) @app.before_request def b1(): print('b1') @app.after_request def a1(environ): print('a1') return environ @app.route('/index') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run()
訪問首頁:http://127.0.0.1:5000/index,效果以下:
Pycharm輸出:
b1
a1
總結:before_request其實是將視圖函數,append到一個列表中。after_request也是將視圖函數append到一個列表中,可是它對列表作了reverse操做!具體,能夠看源碼。
endpoint主要是作反向解析的,使用url_for模塊,就能夠反向生成url
from flask import Flask,url_for app = Flask(__name__) @app.route('/index',endpoint='n1') def index(): print(url_for('n1')) return 'index' if __name__ == '__main__': app.run(debug=True)
訪問url:
http://127.0.0.1:5000/index
執行輸出:
/index
flask的session默認存儲在哪裏呢?在django中,session默認是保存在表裏面的。
那麼flask的session實際上是保存在 用戶瀏覽器的cookie中
它是如何存儲的呢?看下面一段代碼
from flask import Flask,request,session app = Flask(__name__) app.secret_key = 'fdsa' # 必需要指定這個參數 @app.route('/login') def login(): #認證過程省略... # 設置session session['user_info'] = 'xiao' return '123' if __name__ == '__main__': app.run(debug=True)
訪問登陸頁面,效果以下:
查看請求, 發現一個Set-Cookie。這個cookie的key就是session,值爲一堆字符串。它是已經加密過的!
那麼它是如何實現的呢?看這一行代碼
session['user_info'] = 'xiao'
它在內存中,維護了一個空間,這個空間是一個字典。因爲服務端是單進程,單線程。
全部請求過來時,會排隊。這個字典,會放一個key,這個key就是程序的線程id,value存放用戶信息。
而value是一個字典,好比:{'user_info':'xiao'}
假設有100個用戶,那麼有100個值。大概是這樣的樣子:
{ "線程id": { "user_info": "xiao" }, "線程id": { "user_info": "zhang" }, ... }
返回給瀏覽器時,將內存中的字典作序列化,並作了加密
加完密以後,在cookie中寫了一點數據
key是隨機的,可是vlaue纔是真正的數據
這個時候,flask字典,就清空了。
用戶瀏覽器cookie中就有數據了,可是flask中的數據已經沒有了!
這個時候,若是再來一用戶,也是執行上面的流程。
總之,做爲服務器,我不存儲數據。
那麼問題來了,flask如何作session驗證?
若是以前的用戶來了,它會攜帶cookie。
flask會讀取cookie值,若是發現有,進行解密。若是解密成功,那麼就是已經登陸過了,不然沒有登陸過。
解密以後,它會將數據放到字典中!
那麼讀取時,它會直接從內存中讀取。
關於flask的源碼分析,請參考連接:
http://www.javashuo.com/article/p-yesdfxfy-bc.html
因爲時間關係,步驟略...
關於websocket原理,請參考連接:
http://www.javashuo.com/article/p-kaadeqnc-e.html
flask上下文管理,主要分爲2類:
請求上下文管理
應用上下文管理
因爲時間關係,步驟略...
草稿圖
關於flask上下文管理,請參考連接:
https://www.cnblogs.com/zhaopanpan/p/9457343.html
https://blog.csdn.net/bestallen/article/details/54429629
關於flask面試題,請參考連接:
https://www.cnblogs.com/caochao-/articles/8963610.html
今日內容總結:
內容詳細: 1. websocket原理 a. websocket是一個協議。 websocket解決了一個問題:服務端能夠向客戶端推送消息。 http協議規定: - 請求體請求體 - 一次請求一次響應(無狀態短連接) websocket協議規定: - 握手 - base64(sha1(key + magic string )) - 收發數據(加密) - =127 - =126 - <=125 - 鏈接建立不斷開(持久鏈接) b. 使用 - flask: werkzurg / geventwebsocket - django: wsgiref / channel - tornado: 本身寫全支持:http和ws 2. flask上下文管理 前戲: a. threading.local # 建立threading.local對象 val = threading.local() def task(arg): # threading.local對象.xxx = 123 # 內部,獲取當前線程ID # { # 7800:{'x1':1} # 7180:{'x1':2} # } val.x1 = arg for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() # ####### flask中搞了一個升級版的threading.local() ####### # 建立threading.local對象 val = threading.local() def task(arg): # threading.local對象.xxx = 123 # 內部,獲取當前協程ID # { # 7800:{'x1':1} # 7180:{'x1':2} # } val.x1 = arg for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() b. 棧 後進先出的數據結構 c. 偏函數 保留已知參數 d. 全局變量,flask程序啓動只有一份數據 _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session')) g = LocalProxy(partial(_lookup_app_object, 'g')) 正文:圖 重點總結: 1. flask路由:裝飾器 ***** 2. flask的session,默認寫在瀏覽器cookie中。 *** 3. websocket協議 ***** 4. flask請求上下文管理 ***** 做業: 請求上下文類關係圖
未完待續...