您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關什么是Flask框架,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
一、初識Flask
Flask擴展應用擴展包
二、認識werkzurg,Flask最重要的依賴
Python Web 框架工具包 werkzeug
# 引用werkzurg的功能模塊 from werkzeug.wrappers import Request,Response from werkzeug.serving import run_simple # 底層的用法 def run(environ,start_response): return [b'abcdefg'] if __name__ == '__main__': run_simple('localhost',4000,run) # 監聽端口并執行run函數 # 另一種用法 @Response.application def hello(request): return Response('Hello World!') ''' return到底返回到客戶端什么內容? 1、狀態碼:status code 200,301,404,返回一個響應的客戶端的狀態碼; 2、content-type:告訴客戶端用什么方式解析返回的值; 3、其他的返回頭信息。 ''' if __name__ == __main__: run_simple('localhost',4000,hello)
三、Flask 使用
3.1、簡單的登錄
from flask import Flask as fk , request,render_template as render,redirect,session,make_response app = fk(__name__) app.secret_key = 'abckd' # 設置session 的加密值 @app.route('/',methods=['GET','POST']) def index(): if request.method == 'POST': user = request.form.get('user') pwd = request.form['pwd'] if user == 'admin' and pwd == '123': print(user,pwd) return '登錄成功!' return render('index.html',h2='你好') # home.add_url_rule('/',view_func=index) #第二種路由的聲明方式,必須已“/”開頭 if __name__ == '__main__': app.run(debug=True,host='192.168.0.11',port=5000) ''' 執行werkzurg中的run_simple('localhost',4000,hello) 這里只是socket進行了請求監聽,當瀏覽器發起請求后,執行內部的__call__()方法。 '''
3.2、靜態文件的處理方法
<!-- 使用靜態文件需要刪除 <!DOCTYPE html> --> <html> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/index.css" type="text/css"> <!-- javascript引用時必須添加type="text/javascript" --> <script language="javaacript" src="/statics/jquery.min.js" type="text/javascript"></script> <!-- 推薦使用這樣加載靜態文件 --> <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css"> <!-- url_for(),函數配置靜態文件,一定要在Flask類中設置靜態文件的路徑和別名,藍圖中設置靜態文件路徑和別名是 不能使用的 --> </head> <body> <h2>index</h2> <h2>{{ h2 }}</h2> <form action="/" method="POST"> <input type="text" name="user" > <input type="password" name="pwd"> <input type="submit" value="提交"> </form> </body>
使用 url_for 函數獲取靜態資源時,必須在實例化 Flask 對象的時候設置 static_url_path(別名),static_folder(靜態文件路徑)。
from flask import Flask from .views.index import home def shb(): app = Flask(__name__,static_url_path='/static',static_folder='./public',template_folder='./template') ''' PS: 1、static_folder的路徑一定要設置正確。 2、static_url_path的值必須是’/static‘,其他測試無效。 3、url(’static‘,filename='靜態文件路徑') 第一個值必須是’static‘,其他測試無效。 4、template_folder 配置注意存放路徑。 5、藍圖中就不再配置存放靜態文件的路徑和引用別名了;模板也不用再配置,這里是全局配置。 ''' app.register_blueprint(home,url_prefix="/api") return app
3.3、Flask 簡單運用
from flask import Flask,render_template,request,redirect,session app = Flask(__name__) # __name__ 可以修改為任意字符串,并可以傳入多個參數 app.secret_key = 'abckd' # 設置session加密多余字符串 # 路由裝飾器,必須已“/”開頭 @app.route('/login',methods=['GET','POST']) # 定義與路由裝飾器匹配的執行函數 def login(): print(request.method) # request 需要導入,獲取請求的信息 session['key] = value # 設置session值 session.get('key') # 獲取session的值 return render_template('login.html',**{key:value}) #return render_template('login.html',key=value) if __name__ == '__main__': app.run(url,prot)
3.4、Flask 的實現基礎
Python Threading 線程模塊用法
3.4.1、Threading.local 多線程
作用:為每個線程創建一個獨立的空間,使得線程對自己空間中的數據進行操作(數據隔離)。
import threading from threading import local local_obj = local() # 實例化local對象 def task(i): local_obj.xxx = i # 為local對象設置一個參數 print(local_obj.xxx,i) # 獲取local對象中的參數 # threading.get_ident() 獲取線程的唯一標示 print(threading.get_ident(),i) for i in range(10): t = threading.Thread(target=task,args(i,)) # 創建線程 t.start() # 開始執行線程
3.4.2、根據字典自定義類似Threading.localz
import threading import greenlet # 獲取協程信息 DIC = {} def task(i): # 獲取協成的唯一標記 # indent = greenlet.getcurrent() # treading.get_ident() 獲取線程的唯一標記 indent = treading.get_ident() if indent in DIC: DIC[indent]['xxx'] = i else: DIC[indent] = {'xxx':i} print(DIC[index][xxx],i) # 打印字典中的參數 for i in range(10): t = threading.Thread(target=task,args=(i,)) # 創建線程 t.start() # 開始執行線程
3.4.3、自定義升級版Threading.localz
此版本中協程與線程可以完全的兼容,完成對請求的數據隔離。 為什么需要給線程和協程數據進行隔離? 在多個請求的時候,由于每個請求的信息不相同,所以需要對不同的請求信息進行分類管理(數據隔離),從而防止數據混亂; 這樣在需要使用視圖函數取得用戶請求信息的時候,才能根據不同的信息進行取值和修改。
import threading import time try: import greenlet # 獲取協程信息 get_indent = greenlet.getcurrent except Exception as e: get_indent = threading.get_ident class local(object): # DIC={} def __init__(self): # pass object.__setattr__(self,'DIC',{}) # 通過父類的方法設置類屬性 def __getattr__(self,item): indent = get_indent() if indent in self.DIC: return self.DIC[indent].get(item) else: return None def __setattr__(self,key,value): indent = get_indent() if indent in self.DIC: self.DIC[indent][key] = value else: self.DIC[indent]= {key:value} obj = local() # 類在實例化的時候運行__init__()方法 ''' obj.xx # 對象.方法的時候運行__getattr__()方法,并且把xx當參數傳入 obj.xx = 123 # 對象.方法賦值的時候運行__setattr__()方法,并且把xx和123當參數傳入 ''' def task(i): obj.xxx = i time.sleep(2) print(obj.xxx,i) for i in range(10): t = threading.Thread(target=task,args=(i,)) # 創建線程 t.start() # 開始執行線程
3.4.4、Flask簡單執行流程
3.4.4.1、Flask 的基本執行流程
封裝 requestContext 對象, full_dispatch_request(視圖函數 執行), response返回 從app.run() 開始 -->> Flask的__call__方法-->> wsgi_app (封裝RequestContext(request,session)對象到 localstack) -->> full_dispatch_request(視圖函數 執行) -->> 執行擴展(before_request) ,觸發信號 -->> 獲取response -->> pop reqeust、session -- >> 結束
3.4.4.2、Flask 源碼執行順序
(1)threading local 和 flask的自定義local對象 - 基于本地線程 可以實現線程隔離。 (2)請求到來 封裝 ctx = RequestContext(request,session) ctx -- 放入 Local __storage__ { 'id':{stack:[ctx]} } (3)執行視圖 導入 request print(reqeust) -- >> localproxy __str__ reqeust.method -- >> localproxy __getattr__ reqeust + 1 -- >> localproxy __add__ 調用_lookup_req_object函數,去local中的ctx中獲取reqeust session (4)請求結束 ctx.auto_pop ctx 從 local 中移除
四、Flask中的方法
Flask request 屬性詳解
# Flask 中的模塊 from flask import Flask,render_template,request,redirect,session request.method # 獲取請求的方法 request.args # 獲取get請求的數據 request.args.get('') # 獲取get請求指定的值 request.form # 獲取post請求的數據 request.form.get('') # 獲取post請求指定的值 files = request.files.get('') # 獲取POST上傳的文件信息 files.filename # 獲取上傳的文件名 files.stream # 獲取上傳文件的內容 files.save('文件路徑','上傳文件的內容',) # 保存上傳文件到本地 ''' session 的處理 flask 放入的是加密cookie中的,繼承了字典的所有功能; flask讀取cookie中session對應的值,將該值解密并反序列化成為字典,供視圖函數使用; 當請求結束時,flask會讀取內存中字典的值,進行序列化并加密,寫入到瀏覽器cookie中。 ''' session['key'] = value # 為session賦值 保存在瀏覽器的cookie中 session.get('') # 獲取session的值 del session['key'] # 刪除 # 設置響應頭 rst = make_response('aaa') # 設置返回加密 rst.headers['Access-Control-Allow-Origin'] = '*' # 允許請求的域名 rst.headers['Access-Control-Allow-Methods'] = 'POST' # 允許POST請求 # Flask() 配置項 import_name, # 文件名稱 static_url_path=None, # 靜態文件別名 static_folder='static', # 靜態文件路徑 static_host=None, host_matching=False, subdomain_matching=False, template_folder='templates', # 模板文件路徑 instance_path=None, # 實例文件路徑 instance_relative_config=False, # 實例配置文件相對路徑 root_path=None # 根文件路徑 # Flask 配置文件 app.config['ENV'] 獲取內部的值 'ENV': None, 'DEBUG': None, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), # session保留時間 'USE_X_SENDFILE': False, 'SERVER_NAME': None, # 設置域名 xxx.com 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, # session以什么方式保存保留時間 'MAX_CONTENT_LENGTH': None, # 上傳文件大小限制 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'SQLALCHEMY_DATABASE_URI' : 'mysql://root:root@127.0.0.1/mysql', # 配置數據庫連接 'SQLALCHEMY_TRACK_MODIFICATIONS' : False, # 自定義配置 'SERVER_PORT': 8000, # 端口 'IP_PATH': '127.0.0.1',# 訪問鏈接
# 綁定二級域名的方法 app.url_map.default_subdomain = 'www' # 設置域名前綴 app.config['SERVER_NAME'] = 'testing.com' # 設置域名 app.register_blueprint(public, subdomain='static') # 設置靜態文件 PS:要指定默認的域名(app.url_map.default_subdomain ),不然無法訪問; SERVER_NAME、app.url_map.default_subdomain 在開發環境是不能加,會報404。
五、Flask配置文件
5.1、通過字符串獲取 Class 并運行(反射)
hasattr、setattr、getattr 解釋
hasattr(object, name) 判斷一個對象里面是否有name屬性或者name方法,返回BOOL值,有name特性返回True, 否則返回False。
class test(): name="xiaohua" def run(self): return "HelloWord" t=test() hasattr(t, "name") #判斷對象有name屬性 #輸出:True hasattr(t, "run") #判斷對象有run方法 #輸出:True
setattr(object, name, values) 給對象的屬性賦值,若屬性不存在,先創建再賦值。
getattr(object, name[,default]) 可以取出來某個屬性,這個屬性如果是一個字段,就得到字段的值了,如果是一個方法,就得到這個方法的指針了,然后可以根據方法的指針來調用方法。
class test(): name="xiaohua" def run(self): return "HelloWord" t=test() setattr(t,'max',30) #在對象中設置max屬性 getattr(t, "name") #獲取name屬性,存在就打印出來。 #輸出:'xiaohua' getattr(t, "run") #獲取run方法,存在就打印出方法的內存地址。 #輸出:<bound method test.run of <__main__.test instance at 0x0269C878>> getattr(t, "run")() #獲取run方法,后面加括號可以將這個方法運行。 #輸出:'HelloWord' getattr(t, "age") #獲取一個不存在的屬性。 ''' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: test instance has no attribute 'age' ''' getattr(t, "age","18") #若屬性不存在,返回一個默認值。 #輸出:'18'
5.2、Flask配置文件的原理
# settings.py 文件 class Foo(object): DEBUG = True
# 獲取settings.py中類的項目 import importlib path = 'settings.Foo' p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) # 如果找到這個類 for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) # 輸出 # DEBUG True
5.3、Flask 三種加載配置方式
在 Flask 程序運行的時候,可以給 Flask 設置相關配置,比如:配置 Debug 模式,配置數據庫連接地址等等,設置 Flask 配置有以下三種方式:
從配置對象中加載(常用):app.config.from_object()
從配置文件中加載:app.config.from_pyfile()
從環境變量中加載(了解):app.config.from_envvar()
以下演練以設置應用程序的 DEBUG(調試模式) 為例,設置應用為調式模式這后,可以實現以下功能。
5.3.1、配置文件
創建配置文件 config.py,在配置文件中添加配置。
app.config.from_pyfile('config.py')
5.3.2、環境變量(了解)
加載指定環境變量名稱所對應的相關配置
app.config.from_envvar('FLASKCONFIG') # 讀取配置 app.config.get()
在視圖函數中使用 current_app.config.get() 注:Flask 應用程序將一些常用的配置設置成了應用程序對象的屬性,也可以通過屬性直接設置/獲取某些配置:app.debug = True
5.3.3、Flask配置文件的原理
# settings.py 文件 class Foo(object): DEBUG = True
# 獲取settings.py中類的項目 import importlib path = 'settings.Foo' p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) # 如果找到這個類 for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) # 輸出 # DEBUG True
5.4、配置對象加載配置
''' app.config # 獲取配置文件對象 app.config['ENV'],app.config['ENV'] = ‘aaa' # 獲取和設置配置文件的值 app.config.from_object(‘settings.Foo’) # 通過外部文件引入配置文件 ''' # settings.py 文件 class 類名: 配置文件key = 配置文件value # 使用 settings.py 文件,文件名任意。 app.config.from_object(‘settings.類名’)
# 主程序運行文件 from flask import Flask from .views.account import bpaccount # 導入視圖 from .views.code import bpcode app = Flask(__name__) app.config.from_object("settings.TestingConfig") #導入配置文件配置類 # 讀取配置文件 app.config['DEBUG'] def create_app(): app=Flask(__name__) app.config.from_object("settings.DevelopmentConfig")#導入配置文件配置類 app.register_blueprint(bpaccount) app.register_blueprint(bpcode) return app
# settings文件 class Config(object): # 公共的配置類 DEBUG =False SECRET_KEY="ADAFA" # 不同應用環境的不同配置類 class ProductionConfig(Config): DEBUG = False class DevelopmentConfig(Config): DEBUG = False class TestingConfig(Config): TESTING=True
六、路由系統
6.1、endpoint 的使用
from flask import Flask, url_for app = Flask(__name__) # endpoint 根據名字反向生成URL '/index' 。如果不設置默認為函數名 url_for( 'index') @app.route('/home',methods=['GET'],endpoint='n1') def index(): print(url_for('n1',name=124)) # 反向生成的URL return 'Index' # app.add_url_rule('/home',view_func=index,methods=['GET'],endpoint='n1') # 第二種定義路由的方法 if __name__ == '__main__': app.run(debug=True) # 修改自動重啟Flask ''' url_for('n1',name=124) 輸出:/home?name=124 '''
6.2、路由傳參
''' 動態路由: /index/<int:nid> 只接收整數 /index/<float:nid> 接收浮點數 /index/<name> 接收字符串,自定義 /index/默認為字符串 ''' from flask import Flask,request,render_template as render,redirect,session,make_response as response,url_for app = Flask(__name__,static_url_path='/static/') @app.route('/<int:nid>',methods=['GET','POST']) # @app.route('/<aname>/<int:aid>',methods=['GET','POST']) def index(nid): print(url_for('index',nid=777)) # print(url_for('index.n1',aname=aname,aid=aid)) if request.method == 'POST': user = request.form.get('user') pwd = request.form.get('pwd') if user == 'admin' and pwd == '123': return render('index.html',success='提交成功!') return render('index.html',h2='首頁') if __name__ == '__main__': app.run() ''' 輸出:/index/777 '''
6.3、 route() 參數
rule # URL規則 view_func # 視圖函數名稱 methods=['GET'] # 請求的方式 endpoint=None # 名稱用于反向生成URL,即:url_for('名稱') strict_slashes=None # 對URL最后的 ‘/’ 符號是否嚴格要求 True:嚴格要求 False:不嚴格要求 redirct_to='/new/<int:nid>' # 重定向 app.config['SERVER_NAME'] = ‘主域名’ subdomain='url' # 配置主域名下子域名訪問地址,寫入'<username>'表示任意子域名
6.4、自定義正則
from flask import Flask,render_template as render,url_for from werkzeug.routing import BaseConverter app = Flask(__name__,static_url_path='/static',static_folder='static') # 自定義正則轉換器 class RegexConverter(BaseConverter): def __init__(self, map, *args):# map 路由傳入的路徑集合 super(RegexConverter, self).__init__(map) # 將接受的第1個參數當作匹配規則進行保存 self.regex = args[0] def to_python(self, value):# 正則匹配URL時觸發 return int(value) # value為匹配到的值 def to_url(self, value): # 方向生成URL觸發 val = super(RegexConverter, self).to_url(value) return val # url_for() nid 的值 # 將自定義轉換器添加到轉換器字典中,并指定轉換器使用時名字為: reg app.url_map.converters['reg'] = RegexConverter @app.route('/<reg("\d+"):nid>',methods=['GET','POST']) def index(nid): print(url_for('index',nid=222)) return render('index.html',h2='index') if __name__ == '__main__': app.run()
6.5、瀏覽器請求URL,Flask視圖函數訪問流程
6.5.1、循環引用的執行流程
6.5.2、找不到視圖函數的解釋
為什么循環引用后,無法找到視圖函數?
在上圖中執行流程中執行了兩次 app = Flask(__name__),第一次在fisher主執行流程時,app被賦值一次,但是在book引用fisher主執行文件以后再次執行了 app = Flask(__name__),這樣fisher主執行流程的app被后執行的book引用app所覆蓋,所以當book引用中流程執行到 if 跳到主執行流程繼續執行時, app 已經是 book 模塊的賦值,因此就會找不到視圖函數。
可以通過 id() 打印app的內存地址來查看兩個app是否是同一個app。
七、FBV 視圖
FBV 視圖:利用函數與路由建立關聯,實現請求響應的控制。 CBV 視圖:通過定義類的方式來建立視圖與路由的關聯。
# CBV視圖 from flask import Flask,views app = Flask(__name__,static_url_path='/static',static_folder='static') class UserViews(views.MethodView): methods = ['GET'] # 設置請求方式 decorators = [] # 設置裝飾器(全部) def get(self,*args,**kwargs): return 'GET' def POST(self,*args,**kwargs): return 'POST' app.add_url_rule('/index',None,UserViews.as_view('uuu')) if __name__ == '__main__': app.run()
7.1、請求相關request
下面是request可使用的屬性,其中'*'是比較常用的。 *form 一個從POST和PUT請求解析的 MultiDict(一鍵多值字典)。 *args MultiDict,要操作 URL (如 ?key=value )中提交的參數可以使用 args 屬性: searchword = request.args.get('key', '') *values CombinedMultiDict,內容是form和args。 可以使用values替代form和args。 *cookies 顧名思義,請求的cookies,類型是dict。 stream 在可知的mimetype下,如果進來的表單數據無法解碼,會沒有任何改動的保存到這個·stream·以供使用。 很多時候,當請求的數據轉換為string時,使用data是最好的方式。這個stream只返回數據一次。 *headers 請求頭,字典類型。 *data 包含了請求的數據,并轉換為字符串,除非是一個Flask無法處理的mimetype。 *files MultiDict,帶有通過POST或PUT請求上傳的文件。 environ WSGI隱含的環境配置。 *method 請求方法,比如POST、GET。 path .script_root .url .base_url .url_root 如果用戶請求如下URL: http://www.example.com/myapplication/page.html?x=y
以上的參數內容如下:
is_xhr 如果請求是一個來自JavaScript XMLHttpRequest的觸發,則返回True,這個只工作在支持 X-Requested-With頭的庫并且設置了XMLHttpRequest。 blueprint 藍本名字。 endpoint endpoint匹配請求,這個與view_args相結合,可是用于重構相同或修改URL。當匹配的時候發生異常,會返回None。 get_json(force=False, silent=False, cache=True) json 如果mimetype是application/json,這個參數將會解析JSON數據,如果不是則返回None。 可以使用這個替代get_json()方法。 max_content_length 只讀,返回MAX_CONTENT_LENGTH的配置鍵。 module 如果請求是發送到一個實際的模塊,則該參數返回當前模塊的名稱。這是棄用的功能,使用blueprints替代。 on_json_loading_failed(e) routing_exception = None 如果匹配URL失敗,這個異常將會/已經拋出作為請求處理的一部分。這通常用于NotFound異常或類似的情況。 url_rule = None 內部規則匹配請求的URL。這可用于在URL之前/之后檢查方法是否允許(request.url_rule.methods) 等等。 默認情況下,在處理請求函數中寫下 print('request.url_rule.methods', request.url_rule.methods) 會打印: request.url_rule.methods {‘GET’, ‘OPTIONS’, ‘HEAD’} view_args = None 一個匹配請求的view參數的字典,當匹配的時候發生異常,會返回None。
7.2、響應相關
from flask import Flask,make_response as response,jsonify,render_template as render,redirect ''' make_response 封裝所有形式的返回響應體,并可以設置返回響應頭 res = response(render('index.html',**{'k1':'v1'})) return res 返回響應體 return '' 返回字符串 return jsonify({'k1':'v1'}) 返回json字符串 return render('index.html',**{'k1':'v1'}) 返回一個文件 return redirect('http://www.baidu.com') 返回重定向URL ''' app = Flask(__name__,static_url_path='/static/') app.secret_key = 'abck' @app.route('/',methods=['GET','POST']) def index(): res = response('index.html') # 封裝了返回字符串響應體 res.headers['xxx'] = 123 # 設置返回響應頭 res.set_cookie = 321 # 設置cookies return res # 返回請求體,請求頭, if __name__ == '__main__': app.run()
7.3、before_request 裝飾器
from flask import Flask,make_response as response,jsonify,render_template as render,redirect,request app = Flask(__name__,static_url_path='/static/') # app.before_request后面的函數,在所有函數執行前執行。 # app級中app.before_request(函數名)直接使用。 # 藍圖中使用裝飾器的方式 @app.before_request def func(): if request.path == '/index': return None return '返回值' # 返回值不是None,不再往后執行,直接返回return的值 # 返回None,才往后執行其他,這里執行index函數 @app.route('/',methods=['GET','POST']) def index(): res = response('index.html') # 封裝了返回字符串響應體 res.headers['xxx'] = 123 # 設置返回響應頭 res.set_cookie = 321 # 設置cookies return res # 返回請求體,請求頭, if __name__ == '__main__': app.run()
八、模板渲染
Flask 模板詳解
8.1、基本語句的使用
# 字符串,字典,列表等基本數據類型,都可以通過python本來的方法操作。 {{ 屬性名.0 }} {{ 屬性名[0] }} {{ 屬性名() }} # html標簽轉換 {{ html標簽|safe }} from flask import Markup Markup('<h2>h2標簽</h2>') # 設置默認 {{ 屬性名|default('你好') }}
8.2、設置全局模板函數
# 設置全局所用的函數 @app.template_global() def sb(a1,a2): return a1 + a2 # 使用:{{ sb(a1,a2) }} # 過濾filter 的使用 @app.template_filter() def sb(a1,a2,a3): return a1 + a2 + a3 # 使用:{{ a1|sb(a2,a3) }}
8.3、模板的繼承
模塊:{% block content %}{% endblock %} 模板文件: <html> <head> <meta charset="UTF-8"> <title>首頁</title> <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css"> </head> <body> <div> {% block content %}{% endblock %} <a href="{{ url_for('admin.index',id=1234)}}">url_for跳轉帶參數</a> </div> </body> </html> ---------------------------------------------------------------------------------------- <!-- 導入模板文件 --> {% extends './template.html' %} {% block content %} <h2> 你好 </h2> {{ h2 }} {% endblock %} 調用模塊: 需要使用模塊文件的引入: {% extents '模板文件' %} 模塊代碼: {% block content %} <h2> 你好 </h2> {{ h2 }} {% endblock %} ------------------------------------------------------------------------------------- 導入模板:{% include '模板文件' %} 宏定義:{% macro ccc(name,type='text',value='') %} # 相當于定義def 函數 <input type="{{ type }}" name="{{ name }}"/> <input type="submit" value="提交"/> {% endmacro %} 使用宏:{{ ccc('n1') }}
8.4、url_for生成靜態文件URL連接
''' # 常規構造靜態文件鏈接 1.包含可變部分的動態路由,url_for(endpoint,_external=True,**kwargs)以視圖函數端點名和可選參數作為參數, 當_external為True時返回url絕對路徑,否則返回相對路徑 2.url_for(endpoint,_external=True,**kwargs)中可以為動態靜態文件部分傳遞參數, 如url_for('.static',_external=True,filename='js/html5shiv.min.js'), 返回的url是http://localhost/static/js/html5shiv.min.js ''' # 不在藍圖中使用 url_for 構建靜態文件路徑 # http://localhost/static/js/fixes/html5shiv.min.js print url_for('static', filename='js/fixes/html5shiv.min.js', _external=True) ''' PS:藍圖中endpoint必須加上當前命名空間前綴表示當前命名空間,如定義的main藍圖,必須如下使用 url_for('main.static',_external=True,filename='js/html5shiv.min.js') ''' # 藍圖中使用url_for構建反向連接時必須添加藍圖名 # http://localhost/static/js/fixes/html5shiv.min.js print url_for('.static', filename='js/fixes/html5shiv.min.js', _external=True) print url_for('main.static', filename='js/fixes/html5shiv.min.js', _external=True)
8.5、錯誤頁面設置
定義錯誤頁面用裝飾器 @app.errorhandler() 來完成,在定義的過程中必須遵循的是在 Flask 直接實例化下定義,不然會定義不成功。
# _*_ coding:utf-8 _*_ from flask import Flask, render_template as render app = Flask(__name__) @app.errorhandler(404) def page_not_found(error): return render('/home/404.html'), 404
九、Flash和特殊裝飾器
9.1、flash 消息閃現
在使用 flash() 時會使用到session,所以需要在配置文件中配置 SECRET_KEY。
from flask import flash,get_flashed_messages flash('',category='數據分類屬性') # 設置 flash('Error',category='error') get_flash_messages() # 獲取 get_flash_messages(category_filter=['數據分類屬性']) # 通過分類獲取 ''' flash 實現原理: flash基于session來處理內容,先將flash('')中的值存入session中,再通過session的pop移除,達到用一次就消失的效果。 ''' # session自己實現 session.pop('屬性名')
HTML中獲取 flash() 信息
在模板引擎中怎樣定義一個變量;通過關鍵字 set 定義一個變量。category_filte 過濾返回的類別。
{% set messages = get_flash_messages(category_filter=["error"]) %}
Flask消息閃現文檔
9.2、Flask中間件
9.2.1、特殊裝飾器
#設置全局模板函數 @template_global() @template_filter() # app.route視圖函數執行前執行,只運行第一次 @app.before_first_request def x1(): print('before_first') # app.route視圖函數執行前執行,多個誰先定義誰先執行 @app.before_requesr def x2(): print('before') # app.route視圖函數執行后執行,必須有參數和返回值,多個誰后定義誰先執行 @app.after_request def x3(response): print('after') return response #定義404 @app.errorhandler(404) def not_fourd(arg): return '404'
9.2.2、中間件
''' Flask的中間件需要通過自定義方法,去替換源碼中的相關方法,利用在程序獲得請求時才運行__call__()的特性, 來創建中間件,從而完成中間件的功能。 ''' class Middleware(object): def __init__(self, old): self.old = old def __call__(self, *args, **kwargs): print('前') ret = self.old(*args, **kwargs) print('后') return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app)
十、藍圖
為開發者提供一個目錄結構,讓開發更規范,可以將特殊裝飾器加到藍圖中,并根據不同的返回內容設置不同的域名前綴。
為什么flask的根目錄不是第一個flask03,而是第二個flask03?
因為在對 Flask(__name__) 進行實例化時,__name__ 所獲取的值決定了Flask根目錄的位置。
10.1、藍圖的基本模型
10.1.1、主路由視圖函數
__init__.py
from flask import Flask # 導入定義的藍圖模塊 from .views.index import n def app_view(): app = Flask(__name__,) # 注冊,url_prefix指定打開URL的訪問集 http://127.0.0.1/app/1 http://127.0.0.1/app/2 app.register_blueprint(n,url_prefix='/app')# 添加了url_prefix 模板文件靜態文件也需要添加'/app' return app
app.py
from flask03 import app_view app = app_view() print(app) if __name__ == '__main__': app.run()
10.1.2、分路由視圖函數
index.py
#coding:utf8 from flask import Blueprint # ps:藍圖名不能與視圖函數名一致 n = Blueprint('index',__name__,template_folder='../xxx', static_folder='../statics',static_url_path='/statics') ''' 在藍圖中,必須帶上“藍圖函數.endpoint名” url_for('index.n1',name=name) url_for('.n1',name=name) ''' @n.route('/home/<name>',methods=['GET'],endpoint='n1') def index(name): print(name) print(url_for('index.n1',name=name)) return 'home' ''' 訪問域名:http://127.0.0.1:5000/api/home/123 輸出:“name”:123 “url_for('index.n1',name=name)”:/api/home/123 '''
10.2、大項目藍圖目錄結構
十一、Flask上下文管理
11.1、Flask執行順序
上下文管理的內容: request、session、app、g 1、客戶端請求到來時,會將request/session封裝到一個對象 RequestContext(self,environ)中(其中self為app對象, environ為客戶端請求的原始數據); ctx=RequestContext(self,environ) 封裝了 request/session 2、將含有request/session的對象打包,根據線程/協程的唯一標識,作為字典存放在一個 “空間中”(線程/協程唯一標識作為Key,RequestContext對象作為Value), { 線程/協程唯一標識:{ctx:RequestContext對象} .... } 3、視圖函數運行過程 from flask import request,session request.method 當有請求過來時,通過線程/協程唯一標識找到,存放在空間中的RequestContext對象,再通過對象找到封裝其中的 request/session,最后找到屬性.method。 4、請求結束 session保存到瀏覽器cookie中,并移除字典中的數據,從而結束請求。
11.2、偏函數
import functools def index(a1,a2): return a1+a2 # 函數常規的用法 a = index(12,20) print(a) ''' 利用 functools 模塊實現偏函數; 偏函數只要傳入一個值,其他的值自動傳入 ''' new_func = functools.partial(index,666) a1 = new_func(34) print(a1)
11.3、上下文:執行流程
request 請求執行流程
11.4、上下文session
Flask session 的請求流程
十二、Flask 中的 localProxy 方法
local:維護保存在__storage__字典中的線程/進程;
localStack:視圖系統通過其操作local維護的__storage__字典;
localProxy:它的作用主要是幫助 request 獲取當前應用的HTTP請求信息,伴 request 運行和消失的。
class LocalProxy(object): def __init__(self): pass def __getattr__(self): pass def __setattr__(self): pass def __getitem__(self): pass lp = LocalProxy()
十三、Flask g變量
1、g作為flask程序全局的一個臨時變量,充當著中間媒介的作用,我們可以通過它傳遞一些數據;
2、g保存的是當前請求的全局變量,不同的請求會有不同的全局變量,通過不同的thread id區別;
3、g對象在一次請求中的所有代碼任何地方,都是可以使用的。
g.name='abc'
g變量簡單應用
1、創建一個utils.py文件,用于測試除主文件以外的g對象的使用
# utils.py #encoding: utf-8 from flask import g def login_log(): print u'當前登錄用戶是:%s' % g.username def login_ip(): print u'當前登錄用戶的IP是:%s' % g.ip
2、在主文件中調用utils.py中的函數
#encoding: utf-8 from flask import Flask,g,request,render_template from utils import login_log,login_ip app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' @app.route('/login/',methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: username = request.form.get('username') password = request.form.get('password') g.username = username g.ip = password login_log() login_ip() return u'恭喜登錄成功!' if __name__ == '__main__': app.run()
關于什么是Flask框架就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。