flask 初識
一、flask 中的 返回值
示例:一個簡單的 flask 項目的啟動
該框架的返回值主要包括5類( 字符串、重定向、頁面、json數據、文件(圖片和視頻)等 )
from flask import Flask, redirect, render_template,json,jsonify,send_file app = Flask(__name__) @app.route("/") def index(): # return "hello" # 返回字符串直接返回即可 return redirect("/login") # 重定向 @app.route('/login',methods=["POST","GET"]) # 不寫methods,默認是GET請求, def home(): return render_template('login.html') # 返回html頁面,template設置為 mark derectory @app.route('/json') def jsons(): l = {'name':'cheney'} # return json.dumps(l) # 響應頭:Content-Type: text/html; charset=utf-8 () return jsonify(l) # 響應頭:Content-Type: application/json(返回json標准的字符串 )兩者是響應頭的區別,前端能夠識別 @app.route('/file') def file(): # return send_file('01.mp4') # send_file(),打開文件並返回文件內容(自動識別文件格式) return send_file('22.png') # 返回的是圖片,二進制文件時,背景是特殊顏色 app.run("0.0.0.0",5000,debug=True) # 設置debug=True,修改代碼,項目可以不重啟,如果里面不寫參數,默認是127.0.0.1:5000端口的
二、flask 中的 request
request,是公共變量
from flask import request request.method # 請求方式 'POST' 'GET' request.form # 存放FormData中的數據 to_dict 序列化成字典("username":"chen","password":"123"),表單數據提交的都是formdata類型的 request.args # 獲取URL中的數據 to_dict 序列化成字典 (get請求中的參數,問號之后的) request.files # 序列化文件存儲 save() request.url # 訪問的完整路徑 http://127.0.0.1:8000/login 有參數包括參數 ?a=1&b=2 request.path # 路由地址 (/login) request.host # 主機地址 (127.0.0.1:8000) request.values # 獲取 FormData and URL中的數據,不要用to_dict,會覆蓋 request.json # 如果提交時請求頭中的Content-Type:application/json 字典操作 request.data # 如果提交時請求頭中的Content-Type 無法被識別 將請求體中的原始數據存放 byte request.cookies # 獲取Cookie中的數據 request.headers # 獲取請求頭
文件的保存:
my_file = request.files.get("my_file") my_file.save(my_file.filename) # 可以用原文件的名字,也可以用自己定義的名字和路徑,'./chen',當前路徑
三、Jinja2 語法
flask 中的 Jinja2 類似於 django 中的模板語法(template),兩者做的事情是一樣的,都是將后端傳的內容在前端頁面進行渲染
不同的是:
Jinjia2 用法類似python,取值符合字典列表的規則
template 用法都是用點 . 取值
1、變量的取值
{{ }}
取值類似字典,{{ stu.name }} 、{{ stu[name] }}、{{ stu.get(name) }} 都可以獲取值,django中模板語法只能用 點 取值
2、邏輯代碼
{% %}
3、渲染標簽,安全標簽字符串
標簽字符串 | safe
Markup()
4、全局的
@app.template_global()
5、過濾的
@app.template_filter()
6、宏 macro 用處不大,定義函數,了解即可
示例:
后端 ss.py
from flask import Flask, render_template, Markup app = Flask(__name__) tag = "<input type='text' name='username'>" tag = Markup(tag) # 類似於django中的 Marksafe(),這里用了,前端就不用 tag|safe 了 def func1(a, b): return a + b @app.template_global() def func(a, b): # 類似func1,如果多個頁面中都要用到func函數,那么就需要每個路由函數都傳值函數名,比較麻煩, # 因此使用,template_global()即可,設為全局的 return a + b @app.template_filter() def filter(a, b, c): # 過濾器函數,template_filter(),也是全局的,不需要傳值,模板中直接用即可 print(a) return a + b + c @app.route("/") def index(): return render_template("index2.html", tag=tag, func1=func1) # func1不是全局的,需要傳值 app.run(debug=True)
前端 index2.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> {{ tag }} {{ func1(3,3) }} {{ func(5,5) }} {{ 10 | filter(2,3) }} {% macro create_input(na,ty) %} {{ na }} : <input type="{{ ty }}" name="{{ na }}"> {% endmacro %} {{ create_input("username","text") }} </body> </html>
四、flask 中的 session(利用裝飾器驗證登錄)
1、裝飾器的用法
裝飾器主要是用於對某些程序在運行執行做一些處理操作,
示例:利用裝飾器,計算程序運行的時間
import time def waibu(func): def neibu(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret return neibu @waibu def func(): for i in range(100000000): continue return "OK" print(func()) # 1.7812395095825195 # OK
2、Flask-Session
session也是公共變量
session是用於驗證用戶身份信息的,可以在登錄的時候添加session,訪問其他頁面的時候校驗用戶身份信息。
django:session是存儲在服務端的,
flask:session是加密后存儲在前端的cookies中的鍵值對,節省flask的開銷,
由於Flask中默認Session 存放位置 - 客戶端的Cookies中,加密使用 app.secret_key = "加密字符串" ,加密字符串可以隨便寫,主要是用於序列化和反序列化 session信息,
- 有人說,session放在前端cookies中,會不完全?
由於在加密的時候,該加密方式是添加了字符串的,再進行加密,而字符串是保存在后端的,因此,別人不知道字符串自然也無法解密
- 請求進入視圖函數 帶上cookie 將Session從cookie序列化出來 通過secret_key 反序列化成字典
xxx.py
from flask import Flask, redirect, render_template, request, session app = Flask(__name__) app.secret_key = "DragonFire" # 這里一定要給定字符串,進行加密 @app.route("/login", methods=["POST", "GET"]) # 在涉及到其他請求的時候,一定要添加進來,不寫則請求不能訪問,默認是GET,如果只有GET訪問的話可以不寫 def login(): if request.method == "GET": return render_template("login.html") if request.form.get("username") == "chen" and request.form.get("password") == "123": session["user"] = request.form.get("username") # 登錄成功,將用戶信息添加到session中 ,訪問其他路由的時候,通過session進行驗證即可。 return redirect("/") app.run(debug=True)
login.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post" enctype="multipart/form-data"> 用戶名<input type="text" name="username"> 密碼<input type="password" name="password"> 文件:<input type="file" name="my_file"> <input type="submit" value="登錄"> </form> </body> </html>
3、利用裝飾器驗證session,進行用戶登錄
示例:
from flask import Flask, redirect, render_template, request, session app = Flask(__name__) app.secret_key = "DragonFire" @app.route("/login", methods=["POST", "GET"]) # 登錄不能加裝飾器,驗證session def login(): if request.method == "GET": return render_template("login.html") if request.form.get("username") == "chen" and request.form.get("password") == "123": session["user"] = request.form.get("username") print(session['user']) print(11) return redirect("/index") def wai(func): # 驗證session信息的裝飾器函數 def nei(*args, **kwargs): if session.get("user"): # session取值,不要使用所以["user"]取值,因為不確定時候有鍵,沒有會報key-error錯誤 ret = func(*args, **kwargs) return ret else: return redirect("/login") return nei @app.route("/",methods=['GET'],endpoint='hello') # 不指定endpoint的函數名,會報錯,裝飾器不能使用,另外裝飾器(@wai)要放在下面 @wai # nei = wai(hello) def hello(): return 'hello' @app.route("/index",methods=['GET'],endpoint='index') @wai # nei = wai(index) def index(): # if not session.get("user"): # 可以再每個函數中進行session身份信息的驗證,但是比較麻煩,會有代碼的重復 # return redirect("/login") return render_template("index.html") app.run(debug=True)
總結:
1、裝飾器函數修飾要放在@app.route() 的下面
2、使用裝飾器@wai,沒有在@app.route()中指明 endpoint的路由函數,裝飾器是不能使用的,會報一下錯誤
AssertionError: View function mapping is overwriting an existing endpoint function: nei
為什么會出現這種問題?
使用Flask定義URL的時候,如果出現"AssertionError: View function mapping is overwriting an existing endpoint function"這個異常信息,就說明定義了多個同名的視圖函數,只需要改成不同的函數名即可。 這是為什么呢? 原來flask中url跟視圖函數並不是直接對應的,而是有一個中間者-endpoint。 三者之間的關系是這樣的: ``` url---->endpoint---->view_function ``` 它們是一對一的關系,在注冊add_url_rule的時候,如果不指定endpoint,那么endpoint就會默認為函數名字,如果同一個endpoint於多個url注冊的話,就會發生沖突,從而拋出異常。
3、解決辦法就是:在route中指明 endpoint="路由函數名"
方式一:在route中指明 endpoint="路由函數名",上面的示例采用的是該方式

源碼中解析:
如果不指定endpoint,那么會默認是傳入@app裝飾器的原函數,這里也就是@wai 裝飾后的函數名 nei,多個函數都裝飾的時候就會重復,所以會報錯

方式二、利用functools保持原來的函數名

