路由系統
1 程式碼演示 2 3 from flask import Flask 4 5 app = Flask(__name__) 6 7 app.debug = True 8 # 路由基本使用 9 # @app.route('/', methods=['GET']) 10 # @app.get() 11 # @app.post() 12 def index(name): 13 print(name) 14 return 'hello world' 15 16 17 # 自己註冊路由,看route原始碼,等同於django的path 18 app.add_url_rule('/index', endpoint=None, view_func=index, methods=['GET'],defaults={'name': 'zhangsan'}) 19 20 if __name__ == '__main__': 21 app.run() 22 23 ''' 24 route()原始碼解析,本質 25 使用的時候@app.route('/', methods=['GET'])---decorator---index=decorator(index) 26 def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 27 def decorator(f: T_route) -> T_route: 28 # 1.如果沒有傳endpoint,那麼就是None 29 endpoint = options.pop("endpoint", None) 30 # 2.self app物件,是Flask類的例項---flask類中的add_url_rule方法方法是路由的本質 31 self.add_url_rule(rule, endpoint, f, **options) 32 return f 33 return decorator 34 於是註冊路由,我們可以不用裝飾器,可以自己寫 35 ''' 36 37 38 ------------------------------------------------------------------------------------ 39 40 # 2 route的引數,其實就是add_url_rule的引數 41 # rule, URL規則,路徑 42 # view_func, 檢視函式名稱 43 # defaults = None, 預設值, 當URL中無引數,函式需要引數時,使用defaults = {'k': 'v'}-為函式提供引數 ---》django中也有,叫kwargs 44 # endpoint = None, 名稱[別名],用於反向生成URL,即: url_for('名稱') 45 # methods = None, 允許的請求方式,如:["GET", "POST"] 46 # strict_slashes = None 對URL最後的 / 符號是否嚴格要求 47 ''' 48 @app.route('/index', strict_slashes=False) 49 #訪問http://www.xx.com/index/ 或http://www.xx.com/index均可 50 @app.route('/index', strict_slashes=True) 51 #僅訪問http://www.xx.com/index 52 ''' 53 # redirect_to = None重定向到指定地址 54 ''' 55 @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 56 ''' 57 58 # subdomain = None子域名訪問 59 60 61 62 63 # 3 轉換器 app.add_url_rule('/index/<int:pk>') 64 DEFAULT_CONVERTERS = { 65 'default': UnicodeConverter, 66 'string': UnicodeConverter, 67 'any': AnyConverter, 68 'path': PathConverter, 69 'int': IntegerConverter, 70 'float': FloatConverter, 71 'uuid': UUIDConverter, 72 }
。
。
。
偏函式
1 from functools import partial # 內建的 2 3 4 def add(x, y, z): 5 return x + y + z 6 7 8 res = add(1, 2, 3) 9 print(res) 10 11 # 偏函式 12 add_1 = partial(add, 1) # 提前傳值 13 print(add_1(2, 3)) 14 15 16 17 後期去找資料文件再補充
。
。
CBV 基於類的檢視
基本使用
1 from flask import Flask, url_for 2 from flask.views import MethodView 3 4 app = Flask(__name__) 5 app.debug = True 6 7 8 class IndexView(MethodView): 9 def get(self): 10 return 'get請求' 11 12 def post(self): 13 return 'post請求' 14 15 16 # name其實就是endpoint的別名,且必須傳,如果都傳,以endpoint為準 17 # app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view(name='jh')) 18 19 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 20 if __name__ == '__main__': 21 app.run()
原始碼分析
1 # 0 app.add_url_rule('/index', view_func=IndexView.as_view(name='jh')) 2 3 # 1 as_view 原始碼 4 @classmethod 5 def as_view(cls, name, *class_args) : 6 if cls.init_every_request: 7 def view(**kwargs: t.Any) -> ft.ResponseReturnValue: 8 self = view.view_class( # type: ignore[attr-defined] 9 *class_args, **class_kwargs 10 ) 11 # current_app.ensure_sync 不用看 12 # 當成 return self.dispatch_request(**kwargs) 13 return current_app.ensure_sync(self.dispatch_request)(**kwargs) 14 else: 15 self = cls(*class_args, **class_kwargs) 16 def view(**kwargs: t.Any) -> ft.ResponseReturnValue: 17 return current_app.ensure_sync(self.dispatch_request)(**kwargs) 18 if cls.decorators: 19 # 把view的名字改為 傳入的name,否則它一直叫view--》endpoint沒傳,就報錯 20 # view.__name__ = name 21 for decorator in cls.decorators: 22 view = decorator(view) 23 view.__name__ = name 24 return view 25 26 # 2 變成了 app.add_url_rule('/index', view_func=view) ,view的名字是傳入的name 27 28 # 3 請求來了--》執行view()--->有沒有引數取決於誰?有沒有轉換器,有沒有defaults 29 30 # 4 執行view本質在執行 self.dispatch_request()--> self是 檢視類的物件 31 32 # 5 MethodView 的dispatch_request 33 def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: 34 # 如果是get請求,meth 就是 get方法 35 meth = getattr(self, request.method.lower(), None) 36 # 執行get加括號---》跟django沒有區別 37 return meth(**kwargs)
。
。
模板
1 程式碼示例: 2 3 from flask import Flask, url_for,request 4 from flask.views import MethodView, View 5 6 app = Flask(__name__) 7 app.debug = True 8 9 10 class IndexView(MethodView): 11 def get(self): 12 return 'get請求' 13 14 def post(self): 15 return 'post請求' 16 17 18 class GoodView(View): 19 def dispatch_request(self): 20 if request.method == 'GET': 21 return self.login() 22 23 def login(self): 24 return 'login' 25 26 27 # name其實就是endpoint的別名,且必須傳,如果都傳,以endpoint為準 28 # app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view(name='jh')) 29 30 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 31 app.add_url_rule('/login', view_func=GoodView.as_view(name='login')) 32 if __name__ == '__main__': 33 app.run() 34 35 ------------------------------------------------------------------------------ 36 # 1 前後端混合才用 37 38 # 2 django的dtl,拿到這直接可以用 39 -區別在有的函式不一樣:過濾器,標籤 |safe 40 -if for 41 -取字典,取列表 都完全一樣 42 -include 43 -extends 44 45 # 3 比dtl多的 46 - 函式可以加括號---》就能傳引數
。
。
請求響應
1 from flask import Flask, url_for, request 2 from flask.views import MethodView, View 3 4 app = Flask(__name__) 5 app.debug = True 6 7 8 class IndexView(MethodView): 9 def get(self): 10 # 請求物件 11 # request.method 提交的方法 12 print(request.args) # get請求提及的資料 http://127.0.0.1:5000/index?name=66 13 # request.form post請求提交的資料 14 # request.values post和get提交的資料總和,,在postman中測,資料放在body內 15 # request.cookies 客戶端所帶的cookie 16 # request.headers 請求頭 17 # request.path 不帶域名,請求路徑 18 # request.full_path 不帶域名,帶引數的請求路徑 19 # request.script_root 20 # request.url 帶域名帶引數的請求路徑 21 # request.base_url 帶域名請求路徑 22 # request.url_root 域名 23 # request.host_url 域名 24 # request.host 127.0.0.1:500 25 # request.files 26 # obj = request.files['the_file_name'] 27 # obj.save('/var/www/uploads/' + secure_filename(f.filename)) 28 return 'get請求' 29 30 def post(self): 31 return 'post請求' 32 33 34 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 35 36 if __name__ == '__main__': 37 app.run() 38 39 40 ------------------------------------------------------------------------- 41 響應 42 43 from flask import Flask, url_for, request,make_response,jsonify 44 from flask.views import MethodView, View 45 46 app = Flask(__name__) 47 app.debug = True 48 49 50 class IndexView(MethodView): 51 def get(self): 52 # 1 新手四件套:字串,模板,重定向,json 53 # 2 向cookie中寫入資料 54 res=make_response('get請求') # make_response 放四件套之一都可 55 res.set_cookie('key','lqz',httponly=True,path='/') 56 # 3 向響應頭中寫入資料 57 res.headers['xxxx']='sss' 58 return res 59 60 def post(self): 61 return 'post請求' 62 63 64 65 app.add_url_rule('/index', view_func=IndexView.as_view(name='lqz')) # 66 if __name__ == '__main__': 67 app.run()
session
1 基本使用 2 3 from flask import Flask, url_for, request, session 4 from flask.views import MethodView, View 5 6 app = Flask(__name__) 7 app.debug = True 8 app.secret_key = 'abscdeklx' 9 10 11 @app.get('/') 12 def index(): 13 # 寫入session 14 name = request.args.get('name') 15 session['name'] = name 16 return '寫入session成功' 17 18 19 @app.get('/home') 20 def home(): 21 # 讀取session 22 name = session.get('name') # 取值 23 # session.pop('name') 刪除 24 # session.clear() 清空 25 return 'session中的name是:%s' % name 26 27 28 if __name__ == '__main__': 29 app.run()
不同瀏覽器再開啟設定值取值,都不一樣,不互相影響
# open_session def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: s = self.get_signing_serializer(app) if s is None: return None val = request.cookies.get(self.get_cookie_name(app)) if not val: return self.session_class() max_age = int(app.permanent_session_lifetime.total_seconds()) try: data = s.loads(val, max_age=max_age) return self.session_class(data) except BadSignature: return self.session_class() # save_session def save_session( self, app: Flask, session: SessionMixin, response: Response ) -> None: name = self.get_cookie_name(app) domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) secure = self.get_cookie_secure(app) samesite = self.get_cookie_samesite(app) httponly = self.get_cookie_httponly(app) # Add a "Vary: Cookie" header if the session was accessed at all. if session.accessed: response.vary.add("Cookie") # If the session is modified to be empty, remove the cookie. # If the session is empty, return without setting the cookie. if not session: if session.modified: response.delete_cookie( name, domain=domain, path=path, secure=secure, samesite=samesite, httponly=httponly, ) response.vary.add("Cookie") return if not self.should_set_cookie(app, session): return expires = self.get_expiration_time(app, session) val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore response.set_cookie( name, val, # type: ignore expires=expires, httponly=httponly, domain=domain, path=path, secure=secure, samesite=samesite, ) response.vary.add("Cookie")
其他引數
# 1 雖然操作session,本質還是以cookie形式儲存到瀏覽器中了
-過期時間,httponly
-配置檔案配置
。
。
請求擴充套件
1 # 1 flask中叫請求擴充套件---》本質作用實現像django中介軟體的作用一樣 2 3 # 2 flask也有中介軟體,但是一般不用,用請求擴充套件即可 4 5 # 3 常用的 6 1 before_request 7 2 after_request 8 3 teardown_request 9 4 errorhandler 10 11 12 # 4 案例 13 ''' 14 # 1 before_request : 15 1 請求來進檢視函式之前執行 16 2 多個會從上往下依次執行 17 3 如果返回None,表示繼續下一個 18 4 如果返回了四件套:表示結束,不繼續往後走 19 ''' 20 21 @app.before_request 22 def before01(): 23 print('來了老弟1') 24 # 向請求物件中,放值 25 request.name='lqz' 26 27 @app.before_request 28 def before02(): 29 print('來了老弟2') 30 31 32 ''' 33 # 1 after_request : 34 1 檢視函式執行完,走 35 2 多個會從下往上依次執行 36 3 必須有返回值,是響應物件 37 4 處理跨域,再響應頭中加--》就用它 38 ''' 39 @app.after_request 40 def after01(response): 41 print('走了老弟1') 42 return response 43 @app.after_request 44 def after01(response): 45 print('走了老弟2') 46 response.headers['ssss']='sss' 47 return response 48 49 50 ''' 51 teardown_request 52 -1 無論檢視函式執行成功或失敗,都會走它 53 -2 即便檢視函式執行出異常,也會走 54 -3 一般用來記錄日誌 55 ''' 56 @app.teardown_request 57 def teardown(exc): 58 # exc是檢視函式錯誤物件--》記錄錯誤日誌 59 print(exc) 60 61 62 ''' 63 errorhandler 64 -1 監聽http響應狀態碼 65 -2 全域性異常處理 66 67 ''' 68 @app.errorhandler(404) 69 def error_404(arg): 70 return jsonify({'code':'xxx'}) 71 @app.errorhandler(500) 72 def error_500(arg): 73 return jsonify({'code':'500錯誤了'})
1 案例 2 3 from urllib import request 4 5 from flask import Flask 6 7 app = Flask(__name__) 8 app.debug = True 9 10 11 # before_request:請求來進檢視函式之前執行 12 @app.before_request 13 def before01(): 14 print('來啦') 15 request.name = '張三' 16 17 18 @app.before_request 19 def before02(): 20 print('來啦2') 21 22 23 @app.get('/') 24 def index(): 25 print(request.name) 26 return '成功' 27 28 29 if __name__ == '__main__': 30 app.run()