python Flask web框架
阿新 • • 發佈:2019-03-04
path pretty spa 記錄 run explain 功能 ng- 錯誤頁面 --> 後端自定義前段函數
--> @app.template_global()
--> @app.template_filter()
--> 請求擴展
--> @app.before_first_request
--> @app.before_request
--> @app.after_request
--> 錯誤頁面自定制
--> 閃現
--> 藍圖
--> 中間件
--> 信號
--> 上下文管理
--> threading.local
--> 請求上下文(requestContext)
--> request
--> session
--> 應用上下文:AppContext
--> app(current_app)
--> g
--> 實現細節
--> 利用threading.local 的線程 唯一ID標識符
--> requestcontext對象通過localstack添加到Local 棧中
--> 導入request(session、current_app、g)是localproxy -> 偏函數 ->Localstack -> Local
--> requestcontext的auto_pop -> localstaack.pop ->local中移除
--> 多app應用
--> 技術點:LocalProxy、chain,偏函數
--> 中間件/信號 執行順序
目錄:
--> Flask
--> 配置文件
--> 配置文件解析
--> 配置文件導入
--> 路由
--> 路由參數
--> 常用路由匹配
--> 請求相關 & 響應
--> request 參數
--> response 參數
--> 打包模板和參數
--> 模板 jinja2
--> 模板導入/繼承
--> 前段/後端 安全渲染
--> 前段自定義函數 macro
--> @app.template_global()
--> @app.template_filter()
--> 請求擴展
--> @app.before_first_request
--> @app.before_request
--> @app.after_request
--> 錯誤頁面自定制
--> 閃現
--> 藍圖
--> 中間件
--> 信號
--> 上下文管理
--> 請求上下文(requestContext)
--> request
--> session
--> 應用上下文:AppContext
--> app(current_app)
--> g
--> 實現細節
--> 利用threading.local 的線程 唯一ID標識符
--> requestcontext對象通過localstack添加到Local 棧中
--> requestcontext的auto_pop -> localstaack.pop ->local中移除
--> 多app應用
--> 技術點:LocalProxy、chain,偏函數
--> 中間件/信號 執行順序
falsk 配置文件解析
{ ‘DEBUG‘: get_debug_flag(default=False), 是否開啟Debug模式 ‘TESTING‘: False, 是否開啟測試模式 ‘PROPAGATE_EXCEPTIONS‘: None, ‘PRESERVE_CONTEXT_ON_EXCEPTION‘: None, ‘SECRET_KEY‘: None, ‘PERMANENT_SESSION_LIFETIME‘: timedelta(days=31), ‘USE_X_SENDFILE‘: False, ‘LOGGER_NAME‘: None, ‘LOGGER_HANDLER_POLICY‘: ‘always‘, ‘SERVER_NAME‘: None, ‘APPLICATION_ROOT‘: None, ‘SESSION_COOKIE_NAME‘: ‘session‘, ‘SESSION_COOKIE_DOMAIN‘: None, ‘SESSION_COOKIE_PATH‘: None, ‘SESSION_COOKIE_HTTPONLY‘: True, ‘SESSION_COOKIE_SECURE‘: False, ‘SESSION_REFRESH_EACH_REQUEST‘: True, ‘MAX_CONTENT_LENGTH‘: None, ‘SEND_FILE_MAX_AGE_DEFAULT‘: timedelta(hours=12), ‘TRAP_BAD_REQUEST_ERRORS‘: False, ‘TRAP_HTTP_EXCEPTIONS‘: False, ‘EXPLAIN_TEMPLATE_LOADING‘: False, ‘PREFERRED_URL_SCHEME‘: ‘http‘, ‘JSON_AS_ASCII‘: True, ‘JSON_SORT_KEYS‘: True, ‘JSONIFY_PRETTYPRINT_REGULAR‘: True, ‘JSONIFY_MIMETYPE‘: ‘application/json‘, ‘TEMPLATES_AUTO_RELOAD‘: None, }View Code
falsk 配置文件導入:
# flask 配置文件介紹: # 方式一: # Session, Cookies以及一些第三方擴展都會用到SECRET_KEY值 # app.config[‘SECRET_KEY‘] = ‘123456‘ # app.config[‘DEBUG‘] = True # 方式二:(只有部分可以如此操作) # app.secret_key = ‘123456‘ # 方式三:(導入配置文件的方式) # app.config.from_pyfile(‘setting.py‘) # 方式四:(推薦方式:在配置文件中寫一個類,將配置寫在類裏面,再導入) app.config.from_object(‘setting.Text‘)
方式四 setting文件
# 共有的 class Config(object): SECRET_KEY = ‘123456‘ DEBUG = False class Text(Config): DEBUG = True SECRET_KEY = ‘abcd‘
路由參數
# 路由系統: # 基於裝飾器來實現,但是究其本質是通過下面函數實現的 # app.add_url_rule(rule=‘/路徑‘,endpoint=‘別名‘,view_func=‘視圖函數‘,methods=‘訪問的類型/["GET","POST"]‘) # CBV 的flask 方式: # from flask import views # 配置視圖 # class Text(views.MethodView): # methods = [‘GET‘,‘POST‘] # # 登錄裝飾器 # # decorators = [login_required,] # # def get(self): # return ‘Text_Class_get‘ # # def post(self): # return ‘Text_Class,post‘ # # 配置路由 # app.add_url_rule(rule=‘/text/‘,view_func=Text.as_view(name=‘text‘)) # app.add_url_rule 和 app.route # 參數: # rule: url 規則 # view_func 視圖函數名稱 # defaults=None 默認值,當url中沒有參數 # endpoint=None 反向生成url,不能重名,在使用裝飾器時,沒有導入@wraps(func)則需要區分 # methods=None 允許的請求方式,如:[‘GET‘,‘POST‘] # strict_slashes=None 對URL最後的 / 符號是否嚴格要求 # redirect_to=None 重定向地址 # subdomain=None 子域名訪問,需要配合域名使用View Code
常用路由匹配方式
# 常用路由方式: # @app.route(‘/user/<username>‘) # @app.route(‘/user/<int:post_id>‘) # @app.route(‘/user/<float:post_id>‘) # @app.route(‘/user/<path:PATH>‘) # @app.route(‘/user/‘,methods=[‘GET‘,‘POST‘])View Code
請求相關 & 響應
request
# request # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host # request.files # obj = request=files[‘the_file_name‘] # obj.save(‘/var/www/uploads‘+secure_filename(f.filename))View Code
response
# response # return "字符串" # render_templates(‘html模板‘,返回參數) # return redirect(‘/index.html‘) # 打包模板和參數 # response = make_response(render_template("index.html")) # response 是flask.wrappers.Response類型 # response.delete_cookie("key") # response.set_cookie("key",‘value‘) # response.headers[‘X-something‘] = ‘A value‘ # return responseView Code
模板 jinja2
# 模板:(模板也支持導入,繼承) # 跟 django 都是使用的jinja2 模板 # 前段 安全渲染 {func | safe } # 後端 安全渲染 import Markup 函數 # # 新增功能 # {% macro 自定義函數名(參數,參數N) %} # <span>{{參數}}---{{參數n}}</span> # <span>{{參數}}---{{參數n}}</span> # <span>{{參數}}---{{參數n}}</span> # {% endmacro%} # # # 調用上面的函數 # {{自定義函數(參數)}} # ------------ # 模板內自定義函數(類似django simple_tag) # @app.template_global() # def sb(a1,a2): # return a1 + a2 # 模板中使用方法: # {{sb(1,2)}} # ------------ # 後端自定義前段函數 # @app.template_filter() # def sb2(a1,a2,a3): # return a1 + a2 + a3 # 模板中使用方法: # {{1|sb2(2,3)}}View Code
請求擴展
# 請求擴展 (django中的中間件) # 第一次訪問執行: # @app.before_first_request # def first(*args,**kwargs) # pass # # 先進後出 # @app.before_request # def preocess_request(*args,**kwargs): # # 這裏可以做登錄認證 # print(‘request_1‘) # # @app.before_request # def preocess_request2(*args,**kwargs): # # 這裏可以做登錄認證 # print(‘request_2‘) # # @app.after_request # def preocess_response(response): # print(‘response_1‘) # return response # # @app.after_request # def preocess_response2(response): # print(‘response_2‘) # return responseView Code
錯誤頁面自定制
# # 錯誤頁面 自定制 # # @app.errorhandler(404) # def error_404(arg): # return "頁面不存在!"
閃現
# # 閃現 : 臨時數據操作 如:顯示錯誤信息 # from flask import flash,get_flashed_messages # # @app.route(‘/get‘) # def get(): # data = get_flashed_messages() # # data = get_flashed_messages(category_filter=[‘l1‘]) 分類取數據 # print(data) # return "get" # # @app.route(‘/set‘) # def set(): # flash(‘aaaaaa‘) # # flash(‘aaaaaa‘,category=‘l1‘) #可以數據分類 # return "set"
上下文管理
# 上下文管理: # 1.知道flask 依賴的組件: WSGI、jinja2、Werkzeug,flask 框架是組裝件的粘合劑 # client --- wsgi -----flask --- jinja2 ----werkzeug # 2.flask 用threading.local 做了一個Local對象 存放請求信息 # 引入步驟: # Flask()實例化 -> 將請求數據傳入Flask實例 -> 將數據push 至 _request_ctx_stack,_request_ctx_stack實質是 LocalStack() # LocalStack() 初始化時 又實例化了 Local() ,local初始化 最終以類似列表的方式 保存object.__setattr__(self, ‘__storage__‘, {}) # 請求到來: # --ctx = 封裝requestContext(request,ssision) # --ctx放進Local中 # 執行視圖時 # --導入request # --request ---> LocalProxy對象中 __getattr__獲取對應的請求 # ---調用 _lookup_req_object函數:去local 中醬requestcontext 將獲取到,再去requestcontext中獲取request或session # 請求結束 # --ctx.auto_pop() # --ctx從local中移除 # --> 上下文管理 # --> threading.local # --> 請求上下文(requestContext) # --> request # --> session # --> 應用上下文: AppContext # --> app(current_app) # --> g # --> 實現細節 # --> 利用threading.local的線程唯一ID標識符 # --> requestcontext對象通過localstack添加到Local棧中 # --> 導入request(session、current_app、g)是localproxy -> 偏函數 ->Localstack -> Local # --> requestcontext的auto_pop -> localstaack.pop ->local中移除View Code
信號
# # 示例一:(自定義信號) # from flask.signals import _signals # # xinhao = _signals.signal(‘before-render-template‘)#創建信號 # # #定義函數 # def wahaha(*args,**kwargs): # print("111",args,kwargs) # # # 將函數註冊到信號中,添加到這個列表 # xinhao.connect(wahaha) # # @app.route("/zzz") # def zzz(): # # 信號是通過send 方法 出發的!!!!!!!!! # xinhao.send(sender=‘xxx‘,a1=123,a2=456) #觸發這個信號,執行註冊到這個信號列表中的所有函數,此處的參數個數需要與定義的函數中的參數一致 # print("ok") # return "OK" # --------------------------------------------------------------- # # 示例二:(內置信號使用) # from flask.signals import _signals # # bf = _signals.signal(‘before-render-template‘) # bf2 = _signals.signal(‘template-rendered‘) # # def text(*args,**kwargs): # print("111") # # bf.connect(text) # bf2.connect(text)View Code
信號與中間件的執行順序
# 信號 依賴於 blinker 模塊 (信號只執行記錄,並不能中斷流程,而中間件可以中斷) # pip install blinker # 內置信號 以及執行順序: # --> a 中間件:before_first_request # --->1 appcontext_pushed = _signals.signal(‘appcontext-pushed‘) # 請求app上下文push時執行 # --->2 request_started = _signals.signal(‘request-started‘) # 請求到來前執行 # --> b 中間件:before_request # --->3 before_render_template = _signals.signal(‘before-render-template‘) # 模板渲染前執行 # --->4.template_rendered = _signals.signal(‘template-rendered‘) # 模板渲染後執行 # --> c 中間件:after_request # --> session.save_session() # --->5 request_finished = _signals.signal(‘request-finished‘) # 請求結束後執行 # --->6.request_tearing_down = _signals.signal(‘request-tearing-down‘) # 請求執行完畢後自動執行(無論成功與否) # --->7.appcontext_tearing_down = _signals.signal(‘appcontext-tearing-down‘) # 請求上下文執行完畢後自動執行(無論成功與否) # --->8.appcontext_popped = _signals.signal(‘appcontext-popped‘) # 請求上下文pop時執行 # 發生在2 / 3 / 4 / 5或不執行 # got_request_exception = _signals.signal(‘got-request-exception‘) # 請求執行出現異常時執行 # message_flashed = _signals.signal(‘message-flashed‘) # 調用flask在其中添加數據時,自動觸發View Code
多APP 應用
# 多APP 應用 # web 訪問多app應用時,上下文管理是如何實現的? # from werkzeug.wsgi import DispatcherMiddleware # from werkzeug.serving import run_simple # # app01 = Flask(‘app01‘) # app02 = Flask(‘app02‘) # # @app01.route(‘/index‘) # def app01_index(): # return "app01" # # @app02.route(‘/index‘) # def app02_index(): # return "app02" # # app = DispatcherMiddleware(app01,{ # ‘/app02前綴‘:app02, # }) # # if __name__=="__main__": # run_simple(‘localhost‘,8002,app)View Code
session 相關
#&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& # 使用session 前 必須配置SECRET_KEY!!! # session 操作:(session就相當於是一個字典!) # session[‘類型‘] = 值 # session.pop[‘類型‘] # del session[‘類型‘] #&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
session 第三方組件(自定制session保存位置)
# flask session 機制 ‘‘‘ ->請求剛進來:獲取隨機字符串,存在,則去容器 中獲取原來的個人數據,否則創建一個空的容器 ->對象(隨機字符串,{請求數據}) ->視圖:讀取內存中對象 ->響應:內存對象 將對象數據保存到數據庫(沒有指定數據庫的話 保存在內存中),把隨機字符串寫到用戶cookie中 ‘‘‘ # 使用 方式一 # flask-session 組件 # from flask_session import Session # import pymongo # # app.config[‘SESSION_TYPE‘] = ‘mongodb‘ # session類型為redis # # app.config[‘SESSION_MONGODB‘] = pymongo.MongoClient(‘localhost‘,27017) # app.config[‘SESSION_MONGODB_DB‘] = ‘text‘ # app.config[‘SESSION_MONGODB_COLLECT‘] = ‘col‘ # # app.config[‘SESSION_PERMANENT‘] = True # 如果設置為True,則關閉瀏覽器session就失效。 # app.config[‘SESSION_USE_SIGNER‘] = False # 是否對發送到瀏覽器上session的cookie值進行加密 # app.config[‘SESSION_KEY_PREFIX‘] = ‘session:‘ # 保存到session中的值的前綴 # # Session(app) # 使用 方式二 # from flask_session import MongoDBSessionInterface # app.session_interface = MongoDBSessionInterface("參數!")View Code
一些問答
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& # 問題1 多線程時如何體現的? # 問題2 flask的local 中保存數據時,使用列表創建出來的棧,為什麽用棧? # --如果寫web程序,web運行環境,棧中永遠保存1條數據(可以不用棧) # --寫腳本獲取app信息,可能存在app上下文嵌套關系 ‘‘‘ from flask import Flask,current_app,globals,_app_ctx_stack app1=Flask(‘app01‘) app1.debug = False app2=Flask(‘app02‘) app2.debug = False with app1.app_context(): print(_app_ctx_stack._local.__storage__) print(current_app.config[‘DEBUG‘]) with app2.app_context(): print(_app_ctx_stack._local.__storage__) print(current_app.config[‘DEBUG‘]) ‘‘‘ # &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
flask 實現裝飾器方式:引入(wraps)
from functools import wraps # flask 實現登錄裝飾器的功能 def login_required(func): @wraps(func) # @wraps(view_func)的作用: 不改變使用裝飾器原有函數的結構(如__name__, __doc__) # 不使用wraps可能出現的ERROR: view_func...endpoint...map... def wrapper(*args,**kwargs): if session.get(‘user‘): return func(*args,**kwargs) else: return redirect(‘/‘) return wrapper # 裝飾器實現的方式: @app.route(‘/index/‘,methods=[‘GET‘]) @login_required # flask 登錄裝飾器 def index(): return render_template(‘index.html‘,u_list=data) @app.route("/detail/<int:id>",methods=[‘GET‘]) def detail(id): return str(id)View Code
python Flask web框架