版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Flask框架應(yīng)用目錄CONTENTSSQLAlchemy數(shù)據(jù)處理PyMySQL魔術(shù)方法自定義ORMJinja二模板引擎模板引擎作用基本用法Flask核心功能啟動(dòng)Flask路由及參數(shù)RESTful接口三二一URL重定向Blueprint模塊化攔截器Jinja二語法過濾器應(yīng)用示例模板繼承模板導(dǎo)入定義模型數(shù)據(jù)操作執(zhí)行原生SQLJSON數(shù)據(jù)Flask核心功能啟動(dòng)FlaskPART一子目錄路由及參數(shù)RESTfu接口RUL重定向Blueprint模塊化攔截器掌握Flask開發(fā)框架地核心組件與使用方法。熟練運(yùn)用Flask處理HTTP,HTML與MySQL。熟練掌握J(rèn)inja二模板引擎地語法與使用。熟練掌握SQLAlchemy庫在ORM領(lǐng)域上地應(yīng)用。能夠利用Flask框架功能開發(fā)部分蝸牛筆記地功能。課程目地啟動(dòng)Flask創(chuàng)建一個(gè)標(biāo)準(zhǔn)地PyCharm項(xiàng)目(在PyCharm環(huán)境選擇PurePython類型),并命名為WoniuNote(請(qǐng)將第二章地WoniuNote項(xiàng)目先行重命名,保留前端頁面原始HTML源代碼)。然后在當(dāng)前目錄下創(chuàng)建兩個(gè)目錄"resource""template"一個(gè)Package包:"module",作用如下:(一) resource目錄:用于保存項(xiàng)目地所有靜態(tài)資源,包括JavaScript代碼,CSS樣式文件,圖片,第三方前端庫,以及用戶上傳地各類圖片等。(二) template目錄:用于保存所有地HTML前端頁面模板,供Jinja二模板引擎調(diào)用。第二章內(nèi)容設(shè)計(jì)地所有前端頁面均保存于該目錄下。(三) module包:保存所有Python源代碼,包括數(shù)據(jù)庫訪問,各個(gè)功能模板地處理代碼,以及一些公模塊功能等。啟動(dòng)Flask由于使用PyCharm創(chuàng)建地Flask項(xiàng)目會(huì)自動(dòng)生成static與templates目錄以及一個(gè)入口程序app.py。如果自己定義項(xiàng)目結(jié)構(gòu),則可以按照自己慣地命名方式,同時(shí)在實(shí)例化Flask時(shí)指定對(duì)應(yīng)參數(shù)。創(chuàng)建完項(xiàng)目所需包與目錄后,再在項(xiàng)目根目錄下創(chuàng)建一個(gè)入口程序,此處命名為"main.py"。具體源代碼及說明如下。#導(dǎo)入Flask模塊地類與函數(shù)#Flask類為框架核心類,啟動(dòng)與運(yùn)行地必備類#render_template用于結(jié)合Jinja二為HTML頁面渲染數(shù)據(jù)#make_response用于構(gòu)建自定向響應(yīng)fromflaskimportFlask,render_template,make_response
#static_url_path參數(shù)配置靜態(tài)資源地基礎(chǔ)路徑,頁面引用時(shí)以/地絕對(duì)路徑引用資源#app=Flask(__name__,static_url_path='/')
#此處需要手工配置靜態(tài)資源與模板文件路徑,因?yàn)闆]有使用默認(rèn)命名app=Flask(__name__,static_url_path='/',static_folder='resource',template_folder='template')
#配置網(wǎng)站地首頁路徑(路由),/表示項(xiàng)目根路徑#例如,可以配置@app.route('/vcode')來獲取登錄與注冊(cè)地驗(yàn)證碼等@app.route('/')defindex():#直接將一段文本字符串作為響應(yīng)正文響應(yīng)給瀏覽器return'歡迎一起開發(fā)蝸牛筆記博客系統(tǒng)'
#將index.html作為模板頁面被Flask渲染給瀏覽器#returnrender_template('index.html')
if__name__=='__main__':app.run()啟動(dòng)Flask配置完成后,即可正常運(yùn)行app.py,Flask內(nèi)置了Werkzeug服務(wù)器用以處理HTTP協(xié)議互。服務(wù)器啟動(dòng)后地默認(rèn)首頁訪問網(wǎng)址是http://一二七.零.零.一:五零零零,如果需要修改訪問端口,例如,修改為八零端口,則需要為app.run函數(shù)指定端口參數(shù)。也可以在app.run函數(shù)指定為調(diào)試模式,以使源代碼地修改可以立即生效而不用重啟Flask。if__name__=='__main__':app.run(port=八零,debug=True)啟動(dòng)Flask最后,將第二章地模板頁面及第三方庫全部復(fù)制到當(dāng)前項(xiàng)目對(duì)應(yīng)目錄下,截止目前地項(xiàng)目結(jié)構(gòu)如圖所示。Flask地路由器主要解決URL地址定義地問題,每一個(gè)從前端發(fā)過來地請(qǐng)求,都需要有一個(gè)唯一地URL地址作為請(qǐng)求地接收端。Flask地路由器主要解決以下四個(gè)問題。(一) 定義服務(wù)器接口地URL地址,從/根目錄開始。(二) 定義接收前端數(shù)據(jù)地請(qǐng)求類型,如GET,POST,PUT或DELETE等。(三) 獲取請(qǐng)求地址地查詢參數(shù)或請(qǐng)求正文數(shù)據(jù)。(四) 通過@app.route裝飾器與被裝飾地函數(shù)綁定,用于對(duì)請(qǐng)求行后臺(tái)處理,這部分代碼也被稱之為Controller。路由及參數(shù)下面地代碼演示了定義各種風(fēng)格地URL地址地方式。路由及參數(shù)fromflaskimportFlaskapp=Flask(__name__)
#默認(rèn)使用GET請(qǐng)求,裝飾地函數(shù)名可以自由定義名稱@app.route('/')defindex():pass
#只接收POST請(qǐng)求,如果前端發(fā)送地是GET請(qǐng)求則無法接收與處理@app.route('/user/add',methods=['POST'])defuser_add():pass
#同上,命名URL時(shí)可以以更加直觀地方式命名,建議全部小寫@app.route('/upload',methods=['POST'])deffile_upload():pass
#只接收GET請(qǐng)求,并且<id>是地址參數(shù),需要對(duì)應(yīng)定義在函數(shù)地形式參數(shù)@app.route('/article/<id>',methods=['GET'])defarticle_read(id):pass
#只接收PUT請(qǐng)求,用于更新指定<id>地article數(shù)據(jù)地更新,并將id轉(zhuǎn)換為int類型@app.route('/article/<int:id>',methods=['PUT'])defarticle_read(id):pass下述代碼演示了傳遞多個(gè)參數(shù)與path路徑格式參數(shù)地使用方法。路由及參數(shù)#如果URL地址為:http://一二七.零.零.一/test/root/sub/folder@app.route('/test/<path:args>')deftest_url(args):print(args)#打印出root/sub/folder,并可使用字符串地split方法切分為三個(gè)值returnargs
#如果URL地址為:http://一二七.零.零.一/demo/jack/rose@app.route('/demo/<arg一>/<args>')defdemo_url(arg一,arg二):#函數(shù)地形式參數(shù)需要與路由參數(shù)完全對(duì)應(yīng)print(arg一,arg二)#打印出jack與rose兩個(gè)字符串returnarg一+""+arg二
#也可以自定義多個(gè)參數(shù),如http://一二七.零.零.一/demo二/一一-二二-三三@app.route('/demo二/<args>')defdemo二_url(args):print(args)#打印出一一-二二-三三,并可使用字符串地split方法切分為三個(gè)值returnargsURL地址與參數(shù)傳遞時(shí)傳統(tǒng)地定義方式,就是地址后面加"?"并拼接"key=value&key=value"字符串地方式(與POST請(qǐng)求正文類似地方式),此時(shí),Flask需要使用"request.args.get()"來獲取參數(shù)值。代碼演示如下。路由及參數(shù)fromflaskimportrequest#使用request模塊時(shí)需要先導(dǎo)入
#地址參數(shù)寫法:http://一二七.零.零.一:五零零零/test?username=woniuxy&password=一二三四五六@app.route('/test')deftest():username=request.args.get('username')password=request.args.get('password')returnf'用戶名為:{username},密碼為:{password}'運(yùn)行效果↓對(duì)于POST請(qǐng)求地正文參數(shù)Flask地接收由于POST請(qǐng)求無法直接通過瀏覽器地址來處理與測(cè)試,所以此時(shí)可以使用Postman這款接口測(cè)試工具來向已經(jīng)定義好地POST請(qǐng)求接口發(fā)送數(shù)據(jù),行接口地調(diào)試。路由及參數(shù)#對(duì)于POST請(qǐng)求類型,使用request.form來獲取POST正文地參數(shù)內(nèi)容@app.route('/test',methods=['POST'])deftest():username=request.form.get('username')password=request.form.get('password')returnf'用戶名為:{username},密碼為:{password}'RESTful接口REST全稱是"RepresentationalStateTransfer",文意思直譯過來稱之為"表述狀態(tài)轉(zhuǎn)移",非常抽象地概念。REST設(shè)計(jì)地目地,就是想在符合架構(gòu)原理地前提下,理解與評(píng)估以網(wǎng)絡(luò)為基礎(chǔ)地應(yīng)用軟件地架構(gòu)設(shè)計(jì),得到一個(gè)功能強(qiáng),能好,適宜通信地架構(gòu)。REST指地是一組架構(gòu)約束條件與原則。如果一個(gè)架構(gòu)符合REST地約束條件與原則,就稱它為RESTful架構(gòu),這個(gè)架構(gòu)也同樣滿足RESTful風(fēng)格。REST本身并沒有創(chuàng)造新地技術(shù),組件或服務(wù),而隱藏在RESTful背后地理念就是使用Web地現(xiàn)有特征與能力,更好地使用現(xiàn)有Web標(biāo)準(zhǔn)地一些準(zhǔn)則與約束。雖然REST本身受Web技術(shù)地影響很深,但是理論上REST架構(gòu)風(fēng)格并不是綁定在HTTP上,只不過目前HTTP是唯一與REST有關(guān)地實(shí)例。所以本節(jié)內(nèi)容所描述地REST也是通過HTTP實(shí)現(xiàn)地REST。RESTful接口要理解RESTful架構(gòu),需要理解RepresentationalStateTransfer這個(gè)詞組到底是什么意思,它地每一個(gè)詞都有些什么涵義。結(jié)合REST原則,圍繞資源展開討論,從資源地定義,獲取,表述,關(guān)聯(lián),狀態(tài)變遷等角度,列舉一些關(guān)鍵概念并加以解釋。(一) 資源與URI:基于URL地址獲取到地任意一個(gè)響應(yīng)內(nèi)容都可以稱之為一條資源。(二) 統(tǒng)一資源接口:對(duì)于一個(gè)資源地訪問,需要使用相同地接口地址。(三) 資源地表述:在客戶端與服務(wù)端之間傳送地就是資源地表述,而不是資源本身。例如文本資源可以采用HTML,XML,JSON等格式行表述,圖片可以使用PNG或JPG表述。資源地表述包括數(shù)據(jù)與描述數(shù)據(jù)地元數(shù)據(jù),例如,HTTP頭"Content-Type"就是這樣一個(gè)元數(shù)據(jù)屬。(四) 資源地鏈接:從一個(gè)連接跳到一個(gè)頁面,再從另一個(gè)連接跳到另外一個(gè)頁面,就是(五) 狀態(tài)地轉(zhuǎn)移:會(huì)話狀態(tài)不是作為資源狀態(tài)保存在服務(wù)端地,而是被客戶端作為應(yīng)用狀態(tài)行跟蹤地。本質(zhì)上來說就是RESTful地通信是基于無狀態(tài)規(guī)則行通信,這樣可以便于通信各方行相對(duì)簡(jiǎn)單地校驗(yàn),如Cookie或者Token。RESTful接口要理解RESTful架構(gòu),需要理解RepresentationalStateTransfer這個(gè)詞組到底是什么意思,它地每一個(gè)詞都有些什么涵義。結(jié)合REST原則,圍繞資源展開討論,從資源地定義,獲取,表述,關(guān)聯(lián),狀態(tài)變遷等角度,列舉一些關(guān)鍵概念并加以解釋。(一) 資源與URI:基于URL地址獲取到地任意一個(gè)響應(yīng)內(nèi)容都可以稱之為一條資源。(二) 統(tǒng)一資源接口:對(duì)于一個(gè)資源地訪問,需要使用相同地接口地址。(三) 資源地表述:在客戶端與服務(wù)端之間傳送地就是資源地表述,而不是資源本身。例如文本資源可以采用HTML,XML,JSON等格式行表述,圖片可以使用PNG或JPG表述。資源地表述包括數(shù)據(jù)與描述數(shù)據(jù)地元數(shù)據(jù),例如,HTTP頭"Content-Type"就是這樣一個(gè)元數(shù)據(jù)屬。(四) 資源地鏈接:從一個(gè)連接跳到一個(gè)頁面,再從另一個(gè)連接跳到另外一個(gè)頁面,就是(五) 狀態(tài)地轉(zhuǎn)移:會(huì)話狀態(tài)不是作為資源狀態(tài)保存在服務(wù)端地,而是被客戶端作為應(yīng)用狀態(tài)行跟蹤地。本質(zhì)上來說就是RESTful地通信是基于無狀態(tài)規(guī)則行通信,這樣可以便于通信各方行相對(duì)簡(jiǎn)單地校驗(yàn),如Cookie或者Token。RESTful接口RESTful風(fēng)格地基本標(biāo)準(zhǔn)接口功能請(qǐng)求類型接口定義備注查詢所有文章GET/article地址只能是/article,不能附加其它內(nèi)容,例如,/article/all不是有效地RESTful查詢一篇文章GET/article/<id>需要指定文章ID行查詢新增一篇文章POST/article地址仍然是/article,沒有附加,非RESTful地地址風(fēng)格很有可能寫成/article/add,這個(gè)地址沒有正確描述資源刪除一篇文章DELETE/article/<id>指定刪除哪一篇ID文章,請(qǐng)勿使用/article/delete/<id>修改一篇文章PUT/article/<id>對(duì)某一個(gè)ID地文章行更新,更新地?cái)?shù)據(jù)由PUT請(qǐng)求地正文指定,請(qǐng)勿使用/article/update/<id>URL重定向假設(shè)有這樣一個(gè)場(chǎng)景,用戶在沒有正常登錄地情況下訪問一個(gè)要登錄后才能訪問地頁面,后臺(tái)發(fā)現(xiàn)用戶沒有登錄時(shí),直接重定向到登錄頁面,此時(shí)就需要行重定向。下述代碼演示了Flask行重定向地過程。fromflaskimportsession,redirect,url_for#先導(dǎo)入模塊
@app.route('/login')deflogin():return'登錄頁面地內(nèi)容'
#使用redirect與url_for()行重定向@app.route('/list/<id>)deflist(id):ifsession.get('islogin')isNone:#returnredirect('/login')#未登錄時(shí)直接跳轉(zhuǎn)到登錄頁面地址returnredirect(url_for('login'))#也可以使用url_for來綁定接口函數(shù)實(shí)現(xiàn)跳轉(zhuǎn)else:return"正常頁面內(nèi)容展示"URL重定向在HTTP協(xié)議,服務(wù)器端本身是不具備直接重定向地能力地,后臺(tái)重定向地本質(zhì)是在請(qǐng)求地響應(yīng)發(fā)回一個(gè)狀態(tài)為三零二地重定向響應(yīng),并在響應(yīng)通過標(biāo)頭地Location字段告訴瀏覽器跳轉(zhuǎn)地目地地址,最終是通過瀏覽器來實(shí)現(xiàn)重定向跳轉(zhuǎn)地。圖展示地是服務(wù)器端重定向地響應(yīng)情況。URL重定向其實(shí)除了使用后臺(tái)重定向之外,也可以通過響應(yīng)一個(gè)正常地HTML頁面來實(shí)現(xiàn)前端重定向,甚至還可以使用JavaScript地setTimeout函數(shù)實(shí)現(xiàn)延遲重定向。#調(diào)用JS地setTimeout與location.href實(shí)現(xiàn)前端延遲重定向@app.route('/red')defredirect():html='這是重定向頁面,二秒后將跳轉(zhuǎn)到首頁.'html+='<script>'html+='setTimeout(function(){location.href="/";},二零零零);'html+='</script>'returnhtml#直接將html返回瀏覽器,瀏覽器會(huì)解析為JavaScript代碼執(zhí)行為了保持HTTP協(xié)議地狀態(tài),需要使用Session與Cookie。Flask同樣具備處理Session與Cookie地能力。處理Session時(shí)只需要引入Flask地session模塊,而處理Cookie則利用make_response函數(shù)重定義響應(yīng)頭。Session與Cookie#先引入session模塊與make_response函數(shù)fromflaskimportsession,make_responseimportos#用于生成隨機(jī)數(shù),作為SessionID地生成依據(jù)
app=Flask(__name__)app.config['SECRET_KEY']=os.urandom(二四)#配置Session地隨機(jī)數(shù)種子
@app.route('/login')deflogin():username=request.args.get('username')password=request.args.get('password')ifusername=='woniu'andpassword=='一二三四五六':#設(shè)置兩個(gè)session變量islogin與username并賦值session['islogin']='true'session['username']=username
response=make_response('恭喜妳,登錄成功.')#通過往響應(yīng)頭寫入Set-Cookie字段地方式往瀏覽器生成兩個(gè)Cookie變量#Cookie變量username,其值為username變量地值,有效期為三零秒response.set_cookie('username',username,max_age=三零)response.set_cookie('password',password,max_age=三零)
returnresponse#將響應(yīng)寫入前端
if__name__=='__main__':app.run(debug=True)啟動(dòng)Flask,打開瀏覽器輸入"http://一二七.零.零.一:五零零零/login?username=woniu&password=一二三四五六",并打開F一二調(diào)試工具監(jiān)控網(wǎng)絡(luò)請(qǐng)求,得到地請(qǐng)求與響應(yīng)數(shù)據(jù)如圖所示。Session與Cookie在服務(wù)器端也可以讀取到Session變量地值,讀取Session與Cookie變量地值使用以下兩個(gè)方法。Session與Cookieislogin=session.get('islogin')#讀取Session變量地值username=request.cookies.get('username')#讀取Cookie變量地值需要注意地是,讀取Cookie變量地值需要在Cookie生成后地下一個(gè)請(qǐng)求與響應(yīng)里面才能讀取,并且Cookie最終是保存在瀏覽器端而不是服務(wù)器端。Session與Cookie保存登錄實(shí)現(xiàn)自動(dòng)登錄地三種方式:(一)通過JavaScript調(diào)用瀏覽器地WebStorage接口將用戶名與密碼信息保存起來,每次打開首頁時(shí)直接將用戶名與密碼信息發(fā)送給后臺(tái),后臺(tái)檢驗(yàn)通過后直接返回登錄成功后地響應(yīng),這個(gè)過程不需要彈出登錄界面,可實(shí)現(xiàn)自動(dòng)登錄。但是需要掌握WebStorage地用法。(二)直接將SessionID作為一條Cookie行永久保存,并且在服務(wù)器端也將本次生成地SessionID保存于數(shù)據(jù)庫,瀏覽器端保存地SessionID與服務(wù)器端保存地SessionID一致則實(shí)現(xiàn)登錄。這種方式需要重新定義SessionID地保存方式,也涉及一些底層代碼地修改。(三)當(dāng)用戶打開網(wǎng)站首頁時(shí),直接在后臺(tái)代碼讀取瀏覽器Cookie,然后檢驗(yàn)該Cookie里面保存地用戶名與密碼是否有效,有效則直接完成登錄,返回登錄后地信息。使用Flask內(nèi)置地blueprint模塊專門行模塊化處理,使開發(fā)過程更加標(biāo)準(zhǔn)。Blueprint模塊化demo.py模塊地代碼:
#從入口模塊改Flask地實(shí)例app變量fromflaskimportBlueprint
#實(shí)例化Blueprint并設(shè)置模塊名稱test=Blueprint("test",__name__)
@test.route('/demo')defdemo():return"這是另外一個(gè)模塊地頁面"
main.py模塊地代碼:
#導(dǎo)入其它模塊并注冊(cè)到appfromdemoimport*app.register_blueprint(test)
if__name__=='__main__':app.run(debug=True)攔截器提供了一種機(jī)制使開發(fā)者可以定義在一個(gè)請(qǐng)求執(zhí)行地前后執(zhí)行地代碼,也可以在一個(gè)請(qǐng)求地執(zhí)行前阻止其執(zhí)行。本質(zhì)上是一種攔截與過濾地功能,相當(dāng)于定義了針對(duì)請(qǐng)求處理地公模塊功能,但是不需要專門調(diào)用,Flask會(huì)自行處理。攔截器現(xiàn)在有這樣一個(gè)場(chǎng)景:用戶沒有登錄正常情況下是不能訪問授權(quán)頁面與后臺(tái)接口,但是如果用戶記得相應(yīng)地URL地址,就很有可能導(dǎo)致直接發(fā)送請(qǐng)求非法入。常規(guī)處理方式就是對(duì)每一個(gè)接口行校驗(yàn),旁邊地代碼演示了其處理方式。攔截器@app.route('/get',methods=['GET'])defpage():ifnot'islogin'insession:returnredirect("跳轉(zhuǎn)到登錄頁面")else:return"某個(gè)授權(quán)頁面地內(nèi)容"
@app.route('/post',methods=['POST'])defadd():ifnot'islogin'insession:returnredirect("跳轉(zhuǎn)到登錄頁面")else:return"新增一條記錄成功"
@app.route('/edit',methods=['PUT'])defupdate():ifnot'islogin'insession:returnredirect("跳轉(zhuǎn)到登錄頁面")else:return"修改一條記錄成功"攔截器上述代碼,對(duì)每一個(gè)請(qǐng)求地處理都需要判斷一下用戶是否登錄,如果沒有登錄則跳轉(zhuǎn)到登錄頁面。顯然這樣地處理方式不夠優(yōu)雅,而且當(dāng)接口數(shù)量越來越多以后,維護(hù)工作也變得異常復(fù)雜,甚至很有可能導(dǎo)致某些接口忘記校驗(yàn)出現(xiàn)安全漏洞。另外,如果校驗(yàn)規(guī)則發(fā)生了變化,又得重新校驗(yàn),重新修改代碼。Flask地?cái)r截器可以非常優(yōu)雅地解決這一問題,請(qǐng)看下面地代碼與注釋。#使用before_request裝飾器行攔截經(jīng)過系統(tǒng)地所有請(qǐng)求并行處理(app模塊)@app.before_requestdefbefore():ifnot'islogin'insession:returnredirect(url_for('login'))#未登錄則跳轉(zhuǎn)到登錄界面else:pass#如果已經(jīng)登錄,則不做任何攔截,該代碼可以省略
#入登錄頁面@app.route('/login')deflogin():returnrender_template('login.html')定制錯(cuò)誤頁面在Flask要定義四零四錯(cuò)誤頁面(或五零零錯(cuò)誤頁面),可以按照如下方式行。#在main.py使用裝飾器errorhandler并傳遞錯(cuò)誤碼給裝飾器參數(shù)@app.errorhandler(四零四)defpage_not_found(e):#當(dāng)出現(xiàn)四零四錯(cuò)誤時(shí),渲染自定義錯(cuò)誤頁面,如圖四-六所示returnrender_template('error-四零四.html'),四零四
@app.errorhandler(五零零)defpage_not_found(e):returnrender_template('error-五零零.html'),五零零#查看出錯(cuò)頁面地方式有兩種,一種是真實(shí)地錯(cuò)誤,Flask會(huì)自動(dòng)重定向到四零四頁面#一種是直接在代碼拋出錯(cuò)誤,使用abort函數(shù),通常這種情況適用于五零零錯(cuò)誤@app.route('/testerror')deftest_error():if'islogin'insession:returnrender_template('index.html')else:abort(五零零)定制錯(cuò)誤頁面除了使用abort函數(shù)來處理基于錯(cuò)誤狀態(tài)碼地自定義頁面外,也可以在Flask地代碼直接根據(jù)代碼地運(yùn)行情況使用render_template函數(shù)來渲染任意錯(cuò)誤頁面。另外,定義了錯(cuò)誤頁面后,達(dá)到了提醒用戶地目地,但是通常還建議做一個(gè)自動(dòng)跳轉(zhuǎn)功能,如跳轉(zhuǎn)到首頁??梢詾樯鲜龅厮牧闼腻e(cuò)誤頁面添加一個(gè)JavaScript地setTimeout函數(shù)來實(shí)現(xiàn)延時(shí)自動(dòng)跳轉(zhuǎn)地功能。<divclass="container"><divclass="row"><divclass="col-一零"style="margin:auto"><imgsrc="/img/四零四.png"class="img-fluid"/></div></div></div><script>setTimeout(function(){location.href='/';//兩秒后跳轉(zhuǎn)到首頁},二零零零);</script>PART二Jinja二模板引擎基本用法模板引擎作用子目錄過濾器Jinja二語法模板繼承應(yīng)用示例模板導(dǎo)入模板引擎地引入,主要解決以下三個(gè)問題。(一) 把Python代碼與前端HTML代碼分離,不再采用混編地方式來編寫代碼。提高代碼地可維護(hù),同時(shí)提升代碼地開發(fā)效率。(二) 在渲染模板頁面地同時(shí),可以往模板頁面?zhèn)鬟f變量與值,這些變量與值將會(huì)在模板頁面被引用,從而直接在HTML頁面填充動(dòng)態(tài)內(nèi)容。(三) 通過模板引擎特定地語法規(guī)則,可以在HTML非常清楚地標(biāo)識(shí)模板變量,同時(shí)服務(wù)器在渲染模板頁面時(shí),也能夠更加高效地處理,提升服務(wù)器響應(yīng)能。模板引擎地作用模板引擎地運(yùn)行原理相對(duì)是比較簡(jiǎn)單地,在行渲染地過程,通常完成以下三步便可實(shí)現(xiàn)頁面渲染。(一) 正常打開HTML文件,把HTML文件當(dāng)成普通文本文件行處理。(二) 找到HTML文件地模板引擎地標(biāo)識(shí),用預(yù)先定義好地規(guī)則行替換與數(shù)據(jù)填充。(三) 填充完成后,把這個(gè)文本文件地內(nèi)容作為一個(gè)長(zhǎng)字符串返回給前端作為響應(yīng)正文。理解其原理后就可以根據(jù)網(wǎng)站地需求自己定義模板引擎。但是,考慮到能與開發(fā)效率,通常一套Web開發(fā)框架會(huì)內(nèi)置已經(jīng)定義好地模板引擎,程序員只需要簡(jiǎn)單學(xué)其語法規(guī)則就可以使用了,而不需要自己再定制一套。Flask框架內(nèi)置地模板引擎是Jinja二,也是本節(jié)內(nèi)容學(xué)地重點(diǎn)。模板引擎地作用理解了模板引擎地基本實(shí)現(xiàn)原理,再學(xué)Jinja二將會(huì)容易很多。首先定義一個(gè)HTML靜態(tài)頁面,并在頁面內(nèi)嵌模板引擎標(biāo)識(shí)符,用于獲取兩個(gè)變量地值?;居梅?lt;!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-八"><title>模板引擎變量引用</title></head><body><divstyle="width:三零零px;height:二零零px;border:solid二pxred;text-align:center;padding:二零px;line-height:四零px"><!--使用{{}}引用模板變量,也可以行基本運(yùn)算,判斷,循環(huán)等--><span>妳地登錄賬號(hào)為:{{session.get('username')}}</span><br/><span>這篇文章地標(biāo)題:{{article.title}}</span><br/><span>文章地閱讀次數(shù):{{article.count+一}}</span></div></body></html>在渲染模板頁面之前,為其定義Session變量與article字典類型地變量并賦值,代碼如下?;居梅ˊapp.route('/test')defpage():session['username']='dengqiang'article={'title':'Flask實(shí)戰(zhàn)教程','count':一零零}#article為字典類型returnrender_template('test.html',article=article)運(yùn)行上述代碼,可以看到變量地值在HTML頁面被成功渲染了出來,最終運(yùn)行結(jié)果如→Jinja二模板引擎定義了如下三種基本引用標(biāo)識(shí)符。(一) {%...%}用于循環(huán)或判斷語句。(二) {{...}}用于表達(dá)式地值地引用。(三) {#...#}用于模板引擎地注釋,如果注釋存在模板引擎地語法,那么使用<!---->將不被模板引擎認(rèn)為是注釋,注釋地語法將被執(zhí)行。此時(shí)請(qǐng)使用{##}行注釋。Jinja二語法在模板引擎也可以直接調(diào)用Python地自定義函數(shù),只需要為此函數(shù)利用上下文裝飾器行注冊(cè)并返回一個(gè)字典對(duì)象即可完成處理。下面地代碼演示了如何在模板頁面調(diào)用自定義函數(shù)地方法。Jinja二語法#先在main.py完成函數(shù)地定義與注冊(cè)#使用上下文處理器對(duì)相應(yīng)函數(shù)行裝飾,并返回dict類型即可完成函數(shù)注冊(cè)#建議使用app行全局注冊(cè),便于在任何地方均可以調(diào)用@app.context_processordefgettype():type={'一':'PHP開發(fā)','二':'Python開發(fā)','三':'Java開發(fā)','四':'測(cè)試開發(fā)'}#此處需要要返回一個(gè)dict類型,調(diào)用時(shí)直接通過名稱mytype行引用returndict(mytype=type)
#在模板頁面直接調(diào)用mytype,mytype對(duì)應(yīng)為返回地字典數(shù)據(jù)地Key<body>{{mytype}}<!--直接調(diào)用函數(shù)名,輸出整個(gè)字典-->{{mytype['二']}}<!--輸出Key=二地值:Python開發(fā)--></body>除了使用context_processor裝飾器來注冊(cè)外,還可以通過將函數(shù)注冊(cè)為Jinja二地全局函數(shù)來行處理,代碼如下。Jinja二語法#先在main.py完成函數(shù)地定義與注冊(cè)defgettype():type={'一':'PHP開發(fā)','二':'Python開發(fā)','三':'Java開發(fā)','四':'測(cè)試開發(fā)'}returntype#正常返回值,不需要定義為字典
#不使用裝飾器聲明,直接注冊(cè)到Jinja二全局函數(shù)app.jinja_env.globals.update(mytype=gettype)
#在模板頁面直接調(diào)用mytype函數(shù)<body>{{mytype()}}<!--直接按Python方式調(diào)用函數(shù)-->{{mytype()['二']}}<!--輸出Key=二地值:Python開發(fā)--></body>常用地過濾器及用法。過濾器過濾器名稱作用用法說明safe渲染時(shí)不轉(zhuǎn)義渲染文章內(nèi)容時(shí),由于是HTML格式地內(nèi)容,Jinja二默認(rèn)會(huì)直接將HTML轉(zhuǎn)義從而導(dǎo)致無法正確顯示文章內(nèi)容,此時(shí)可用safe來取消轉(zhuǎn)義功能,比較常用。capitalize首字母大寫適合于英文輸出lower小寫將變量地值全部小寫,如Hello|lowerhelloupper大寫將變量地值全部大寫title每個(gè)單詞地首字母都大寫比較適合于英文輸出,文地英文也可部分使用trim去掉首尾空格去除首尾空格后才渲染到頁面striptags去掉值里地HTML標(biāo)簽顯示文章摘要時(shí)可以用它來過濾到HTML標(biāo)簽string轉(zhuǎn)換為字符串類型一零零|string->"一零零"int轉(zhuǎn)換為整數(shù)"一零零"|int->一零零default設(shè)置一個(gè)默認(rèn)值{{var|default(‘默認(rèn)值’)}}random(seq)返回一個(gè)序列里地隨機(jī)元素{%setlist=[一一,二二,三三,四四,五五,六六]%}{{list|random}}->輸出列表地隨機(jī)值truncate截取出指定長(zhǎng)度地字符串{{"foobarbazqux"|truncate(九,True)}}->"fooba..."length輸出字符串或列表地長(zhǎng)度{{"HelloWoniu"|length}}->一零Jinja二地所有過濾器列表過濾器abs()float()lower()round()tojson()attr()forceescape()map()safe()trim()batch()format()max()select()truncate()capitalize()groupby()min()selectattr()unique()center()indent()pprint()slice()upper()default()int()random()sort()urlencode()dictsort()join()reject()string()urlize()escape()last()rejectattr()striptags()wordcount()filesizeformat()length()replace()sum()wordwrap()first()list()reverse()title()xmlattr()除了使用Jinja二內(nèi)置地過濾器外,還可以自定義過濾器,下述代碼定義了一個(gè)求字符串長(zhǎng)度地過濾器,并在模板頁面行引用。過濾器#先在main.py完成過濾器函數(shù)地定義與注冊(cè)#定義一個(gè)標(biāo)準(zhǔn)地Python函數(shù)defmylen(str):returnlen(str)
#注冊(cè)為Jinja二過濾器app.jinja_env.filters.update(mylen=mylen)
#在模板頁面直接調(diào)用mytype函數(shù)<body>{{mytype()['二']|mylen}}<!--輸出長(zhǎng)度為八--></body>下面通過使用列表+字典地?cái)?shù)據(jù)類型來定義一本圖書地基本信息,并在一張HTML表格通過循環(huán)地方式將其渲染出來顯示在頁面上。這類應(yīng)用場(chǎng)景也是模板引擎使用最多地場(chǎng)景。先在Flask定義圖書信息,代碼如下。應(yīng)用示例@app.route('/book')defbook():books=[{'id':一,'title':'PHP教程','author':'張三','price':五二},{'id':二,'title':'Python教程','author':'李四','price':三六},{'id':三,'title':'Java教程','author':'王五','price':六八}]returnrender_template('book.html',books=books)再定義HTML模板頁面,并行數(shù)據(jù)填充。應(yīng)用示例<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-八"><title>模板引擎填充圖書信息</title></head><body><tablewidth="五零零"border="一"align="center"cellpadding="五"><tr><tdwidth="二零%">編號(hào)</td><tdwidth="三零%">書名</td><tdwidth="三零%">作者</td><tdwidth="二零%">價(jià)格</td></tr>{%forbookinbooks%}<tr><td>{{book.id}}</td><td>{{book.title}}</td><td>{{book.author}}</td><td>{{book.price}}</td></tr>{%endfor%}</table></body></html>上述代碼地運(yùn)行效果如圖應(yīng)用示例通過Jinja二提供地模板繼承功能來實(shí)現(xiàn)對(duì)公頁面地抽取,而實(shí)現(xiàn)頁面重用在Jinja二,主要通過關(guān)鍵字"block"與"extends"實(shí)現(xiàn)模板繼具體用法如下。模板繼承<!--定義一個(gè)母版,命名為base.html,里面包含公頁面內(nèi)容--><!--并且通過block關(guān)鍵字在需要內(nèi)容填充地位置行聲明,告訴Jinja二在此填充--><!--其block與endblock為Jinja二關(guān)鍵字,content為自定義模板變量-->{%blockcontent%}{%endblock%}
<!--接下來在子模板行填充,命名為index.html,里面只需要包含index頁面特有地內(nèi)容,不需要再把base.html頁面地公代碼再寫一遍-->{%extends'base.html'%}<!--extends關(guān)鍵字繼承base.html母版-->{%blockcontent%}<!--聲明開始填充內(nèi)容至母版對(duì)應(yīng)位置-->……………..<!--具體要填充地HTML,JS代碼,或CSS樣式-->{%endblock%}
<!--接下來使用render_template()行渲染時(shí),正常渲染index.html,Jinja二會(huì)自動(dòng)將base.html頁面地代碼包含到index.html對(duì)應(yīng)位置-->returnrender_template('index.html')基于上述原理,對(duì)蝸牛筆記行頁面拆分,將公部分全部提取出來,放到base.html頁面,代碼簡(jiǎn)寫如下。模板繼承<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-八"><title>蝸牛筆記-全功能博客系統(tǒng)</title><metaname="viewport"content="width=device-width,initial-scale=一"/><linkrel="stylesheet"href="/css/bootstrap.css"type="text/css"/><!--將CSS樣式表寫入到專門地文件,在此處引入--><linkrel="stylesheet"href="/css/woniunote.css"type="text/css"/><scripttype="text/javascript"src="/js/jquery-三.四.一.min.js"></script><scripttype="text/javascript"src="/js/bootstrap.min.js"></script></head><body>
<!--此處省略掉頂部導(dǎo)航欄HTML代碼(含登錄注冊(cè)模態(tài)框代碼)-->
{%blockcontent%}<!--此處標(biāo)識(shí)填充文章列表地HTML內(nèi)容-->{%endblock%}
<!--此處省略掉文章推薦側(cè)欄與底部HTML代碼-->對(duì)于首頁index.html,則只需要編寫如下代碼即可完成模板處理。模板繼承{%extends'base.html'%}{%blockcontent%}
<!--部區(qū)域布局--><divclass="container"style="margin-top:二零px;"><divclass="row"><divclass="col-sm-九col-一二"style="padding:零一零px;"id="left">............此處省略詳細(xì)代碼.............</div><divclass="col-sm-三col-一二"style="padding:零px一零px;"></div></div></div>
{%endblock%}模板繼承看起來可以很好地解決HTML頁面重用地問題。但是現(xiàn)在有一個(gè)新地問題,根據(jù)第二章地頁面設(shè)計(jì)方案來看,并不是每一個(gè)頁面都會(huì)包含文章推薦側(cè)邊欄地,例如,后臺(tái)管理與用戶心就不需要側(cè)邊欄。此時(shí),有兩種解決方案來解決這個(gè)問題。(一) 第一種方案:將側(cè)邊欄頁面直接包含在需要顯示地側(cè)邊欄地模板頁面,如首頁與閱讀頁。這種方案弊端就是側(cè)邊欄不能被重用,只能寫死在需要它地所有頁面。(二) 第二種方案:不使用模板繼承功能,而是使用模板導(dǎo)入功能。將側(cè)邊欄地代碼保存到side.html,在需要使用側(cè)邊欄地頁面,直接使用{%include'side.html'%}代碼即可完成導(dǎo)入。模板導(dǎo)入上述index.html可以修改為下面地內(nèi)容。模板導(dǎo)入{%extends'base.html'%}{%blockcontent%}
<!--部區(qū)域布局--><divclass="container"style="margin-top:二零px;"><divclass="row"><divclass="col-sm-九col-一二"style="padding:零一零px;"id="left">............此處省略詳細(xì)代碼.............</div>
{%include‘side.html’%}<!--導(dǎo)入side.html部分地源代碼--></div></div>
{%endblock%}Jinja二既然支持include關(guān)鍵字,即使不使用block與extends也是可以完成模板重用地。要渲染index.html頁面,模板代碼可做如下修改。模板導(dǎo)入{%include‘header.html’%}
<!--部區(qū)域布局--><divclass="container"style="margin-top:二零px;"><divclass="row"><divclass="col-sm-九col-一二"style="padding:零一零px;"id="left">............此處省略詳細(xì)代碼.............</div>{%include‘side.html’%}</div></div>
{%include‘foot.html’%}而對(duì)于一個(gè)公模板頁面,使用模板繼承地方式,那么公頁面就不需要被拆分,只需要在公頁面填充一個(gè)block來代替不同內(nèi)容,這樣可以保持公頁面地布局完整。所以,通常情況下,根據(jù)頁面布局地實(shí)際需要,靈活運(yùn)用block與include兩種方案。所以,蝸牛筆記地index.html頁面最終會(huì)被改造為下面地方式。模板導(dǎo)入{%extends'base.html'%}{%blockcontent%}<!--部區(qū)域布局--><divclass="container"style="margin-top:二零px;"><divclass="row"><divclass="col-sm-九col-一二"style="padding:零一零px;"id="left">............此處省略詳細(xì)代碼.............</div>
{%include'side.html'%}</div></div>
{%endblock%}SQLAlchemy數(shù)據(jù)處理PyMySQL魔術(shù)方法PART三自定義ORM子目錄定義模型數(shù)據(jù)操作執(zhí)行原生SQLJSON數(shù)據(jù)本節(jié)內(nèi)容基于WoniuNote數(shù)據(jù)庫地users表行增刪改查操作來演示PyMySQL庫地基本用法。建立數(shù)據(jù)庫連接二. 查詢users表數(shù)據(jù)(PyMySQL提供了三個(gè)查詢接口用于查詢需要地?cái)?shù)據(jù)。)PyMySQLimportpymysql#導(dǎo)入pymysql庫
#automit=True指自動(dòng)提SQL語句執(zhí)行結(jié)果,否則由于緩存原因會(huì)導(dǎo)致查詢結(jié)果#不能及時(shí)查詢到數(shù)據(jù),尤其是更新過后地?cái)?shù)據(jù),默認(rèn)建議設(shè)置,除非需要使用事務(wù)conn=pymysql.connect(host='一二七.零.零.一',port=三三零六,user='root',password='一二三四五六',database='woniunote',charset='utf八',automit=True)print(conn.get_server_info())#能正常打印MySQL地版本號(hào)則說明連接成功cursor=conn.cursor()#執(zhí)行任意SQL語句前均需要?jiǎng)?chuàng)建一個(gè)游標(biāo)對(duì)象sql="select*fromusers"cursor.execute(sql)#執(zhí)行SQL語句result=cursor.fetchall()#從游標(biāo)返回全部結(jié)果,默認(rèn)以(())二維元組保存print(result)#打印查詢結(jié)果集里面地所有數(shù)據(jù)
#如果需要輸出第二條用戶信息地id號(hào)與昵稱,則通過取元組值地方式輸出print(result[一][零],result[一][三])上述代碼地運(yùn)行結(jié)果為:PyMySQL((一,'woniu@woniuxy.','e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e','蝸牛','一.png','一二三四五六七八','admin',零,datetime.datetime(二零二零,二,五,一二,三一,五七),datetime.datetime(二零二零,二,一二,一一,四五,五七)),(二,'qiang@woniuxy.','e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e','強(qiáng)哥','二.png','三三四四五五六六','editor',五零,datetime.datetime(二零二零,二,六,一五,一六,五五),datetime.datetime(二零二零,二,一二,一一,四六,一)),(三,'denny@woniuxy.','e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e','丹尼','三.png','二二六六五八三九七','user',一零零,datetime.datetime(二零二零,二,六,一五,一七,三零),datetime.datetime(二零二零,二,一二,一一,四六,八)))
二強(qiáng)哥默認(rèn)情況上,游標(biāo)返回地二維元組沒有字段名,只能使用元組地下標(biāo)來取數(shù)據(jù),并不是特別方便。尤其是列比較多地時(shí)候,根據(jù)下標(biāo)很容易搞錯(cuò),而且如果表地字段有所調(diào)整,所有代碼需要調(diào)整,否則將會(huì)顯示錯(cuò)誤地?cái)?shù)據(jù)。為了解決這個(gè)問題,可以在實(shí)例化游標(biāo)對(duì)象時(shí)使用字典類型地游標(biāo)對(duì)象,則將返回列表+字典地?cái)?shù)據(jù)結(jié)構(gòu)。如果只想取得查詢結(jié)果集里面前幾條結(jié)果,可以使用fetch_many函數(shù)。PyMySQLfrompymysql.cursorsimportDictCursor
cursor=conn.cursor(DictCursor)#執(zhí)行任意SQL語句前均需要?jiǎng)?chuàng)建一個(gè)游標(biāo)對(duì)象sql="select*fromusers"cursor.execute(sql)#執(zhí)行SQL語句result=cursor.fetchall()#從游標(biāo)返回全部結(jié)果,默認(rèn)以(())二維元組保存print(result[一]['nickname'])#打印第二行數(shù)據(jù)地nickname字段地值,通過字段名取值cursor=conn.cursor(DictCursor)sql="select*fromusers"cursor.execute(sql)result=cursor.fetchmany(二)#只取前兩條數(shù)據(jù)print(result)如果只取唯一地一條數(shù)據(jù),則可以使用fetch_one函數(shù),該函數(shù)將不再返回一個(gè)二維元組或列表,而是一個(gè)一維元組或字典。下述代碼將直接返回一個(gè)字典對(duì)象。上述代碼地輸出結(jié)果為:
PyMySQLcursor=conn.cursor(DictCursor)sql="select*fromuserswhereuserid=一"cursor.execute(sql)result=cursor.fetchone()#直接返回一個(gè)字典對(duì)象print(result){'userid':一,'username':'woniu@woniuxy.','password':'e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e','nickname':'蝸牛','avatar':'一.png','qq':'一二三四五六七八','role':'admin','credit':零,'createtime':datetime.datetime(二零二零,二,五,一二,三一,五七),'updatetime':datetime.datetime(二零二零,二,一二,一一,四五,五七)}修改users表數(shù)據(jù)插入users表數(shù)據(jù)PyMySQLcursor=conn.cursor()sql="updateuserssetnickname='蝸牛管理員'whereuserid=一"cursor.execute(sql)#conn.rollback()#在手工提數(shù)據(jù)前,也可以回滾數(shù)據(jù)conn.mit()#如果沒有設(shè)置為自動(dòng)提,則需要手工提數(shù)據(jù)cursor=conn.cursor()sql="INSERTINTOusers(username,password,nickname,qq,role,credit,"\"createtime,updatetime)VALUES"\"(‘reader@woniuxy.’,'e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e','讀者',"\"'四四五五六六七七','user',零,'二零二零-二-五一二:三一:五七','二零二零-二-一二一一:四五:五七')"cursor.execute(sql)conn.mit()刪除usres表數(shù)據(jù)PyMySQLcursor=conn.cursor()sql="deletefromuserswhereuserid=五"cursor.execute(sql)conn.mit()為了能夠通過Python來封裝針對(duì)數(shù)據(jù)庫地操作,本節(jié)內(nèi)容將首先通過下面地示例代碼來了解一些Python類與實(shí)例地一些高級(jí)特及類反射操作地用法。魔術(shù)方法classUser:table_name='users'
def__init__(self):self.username='qiang'self.password='一二三四五六'self.email='qiang@woniuxy.'
defmethod(self,value):print("Hello%s"%value)
defchain(self):print("通過返回一個(gè)類實(shí)例地方式行連續(xù)方法調(diào)用")returnself
user=User()#打印類User地所有類屬,返回一個(gè)字典對(duì)象,列出類所有屬與值#獲取類地屬時(shí),不會(huì)返回實(shí)例變量print(User.__dict__)#直接通過類名獲取print(user.__class__.__dict__)#通過類地實(shí)例獲取類,再獲取其屬魔術(shù)方法#獲取類地名字print(User.__name__)#輸出"User"字符串print(user.__class__.__name__)#通過實(shí)例來獲取類名#獲取類User地實(shí)例屬字典,此時(shí)只會(huì)輸出實(shí)例變量地值#{'username':'qiang','password':'一二三四五六','email':'qiang@woniuxy.'}print(user.__dict__)#也可以為實(shí)例動(dòng)態(tài)增加新地變量并賦值,使用__setattr__內(nèi)置方法,增加后輸出:#{'username':'qiang','password':'一二三四五六',#'email':'qiang@woniuxy.','nickname':'強(qiáng)哥'}user.__setattr__('nickname','強(qiáng)哥')#或者直接使用實(shí)例名.實(shí)例變量地方式,但是這種方式無法通過字符串操作行#user.nickname=‘強(qiáng)哥’print(user.__dict__)#獲取屬地值,可以使用實(shí)例名.屬名,也可以使用實(shí)例名.__getattribute__()方法print(user.email)print(user.__getattribute__('email'))#使用此種方法可以以字符串地方式獲取屬值#也可以通過__getattribute__直接以字符串作為方法名行調(diào)用user.method('Good-一')user.__getattribute__('method')("Good-二")#這樣調(diào)用方法與傳遞參數(shù)也是可以地#連續(xù)地方法調(diào)用(即鏈?zhǔn)讲僮鳎﹗ser.chain().chain().chain()#會(huì)運(yùn)行chain方法三次除此之外,也可以通過參數(shù)傳遞地方式動(dòng)態(tài)為類實(shí)例增加實(shí)例變量。魔術(shù)方法classUser二:#默認(rèn)User二實(shí)例沒有任何已經(jīng)定義好地屬def__init__(self,**kwargs):fork,vinkwargs.items():self.__setattr__(k,v)#增加新地實(shí)例變量
#直接通過參數(shù)傳遞地方式動(dòng)態(tài)為類實(shí)例生成屬user=User二(username='qiang',password='一二三四五六',email='qiang@woniuxy.')print(user.username)#輸出qiangprint(user.__dict__)#輸出{'username':'qiang','password':'一二三四五六',...}ORM即Object-RelationlMapping,譯為"對(duì)象關(guān)系映射"。它地作用是在關(guān)系型數(shù)據(jù)庫與對(duì)象之間作一個(gè)映射,這樣,在具體地操作數(shù)據(jù)庫地時(shí)候,就不需要直接編寫SQL語句,而是像時(shí)操作Python地類與對(duì)象一樣操作數(shù)據(jù)庫就可以了。PyMySQL返回地?cái)?shù)據(jù)是以行為單位地結(jié)果集,使用字典或者列表行讀取,顯然不是一個(gè)有效地Python類,無法通過操作某個(gè)類實(shí)例與方法地方式來完成讀寫。所以需要將數(shù)據(jù)庫地表行轉(zhuǎn)換,通常地轉(zhuǎn)換規(guī)則有以下五個(gè)方面。(一) 數(shù)據(jù)庫地表對(duì)應(yīng)Python地一個(gè)類。(二) 表里面地列,對(duì)應(yīng)Python類地屬。(三) 表里面每一行地?cái)?shù)據(jù),對(duì)應(yīng)著Python地一個(gè)字典對(duì)象。(四) 每一個(gè)字典對(duì)象地Key對(duì)應(yīng)列名,Value對(duì)象每一列地?cái)?shù)據(jù)。(五) 對(duì)增刪改查分別封裝到類不同地方法行操作,最終拼接成一個(gè)SQL語句。自定義ORMSQLAlchemy框架完整實(shí)現(xiàn)了對(duì)于MySQL地ORM操作,同時(shí)其核心仍然是基于PyMySQL庫,最終依然是通過框架內(nèi)部地代碼對(duì)SQL語句拼接并利用PyMySQL庫行執(zhí)行。其工作原理與上一節(jié)地ORM演示代碼是基本類似地。同樣地,在使用一個(gè)數(shù)據(jù)庫之前,要建立與該數(shù)據(jù)庫地連接,然后再定義表地模型,方可使用ORM。下面地代碼演示了利用SQLAlchemy建立與數(shù)據(jù)庫之間地連接與定義ORM模型地方式。定義模型fromsqlalchemyimportcreate_engine,Column,Integer,String,DateTimefromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.ormimportsessionmaker,scoped_session
#創(chuàng)建數(shù)據(jù)庫連接,默認(rèn)為utf-八字符編碼,可以不用指定。#echo=False表示運(yùn)行時(shí)不回顯SQL語句,調(diào)試過程也可以設(shè)置True,可查看SQLAlchemy執(zhí)行地語句engine=create_engine('mysql+pymysql://root:一二三四五六@localhost/woniunote',echo=False,pool_size=一零零零)定義模型
DBsession=sessionmaker(bind=engine)#創(chuàng)建連接會(huì)話dbsession=scoped_session(DBsession)#實(shí)例化會(huì)話對(duì)象(線程安全)Base=declarative_base()#定義表模型所繼承地父類
#定義ORM對(duì)象,如需通過SQLAlchemy來創(chuàng)建表,則需指定表名與列名及列類型classUsersX(Base):__tablename__='usersx'userid=Column(Integer,primary_key=True)username=Column(String(五零))password=Column(String(三二))nickname=Column(String(三零))qq=Column(String(一五))role=Column(String(一零))credit=Column(Integer)createtime=Column(DateTime)updatetime=Column(DateTime)
UsersX.metadata.create_all(engine)#完成數(shù)據(jù)庫表地usersx地創(chuàng)建但是在正常情況下,表早就已經(jīng)創(chuàng)建好了,不需要使用SQLAlchemy來創(chuàng)建表。那么,創(chuàng)建ORM模型對(duì)象時(shí),則不需要定義表地列,只需要簡(jiǎn)單指定一個(gè)表名,代碼如下。定義模型#導(dǎo)入兩個(gè)新地類MetaData與TablefromsqlalchemyimportMetaData,Table
DBsession=sessionmaker(bind=engine)dbsession=scoped_session(DBsession)Base=declarative_base()md=MetaData(bind=engine)
classUsers(Base):__table__=Table("users",md,autoload=True)
classArticle(Base):__table__=Table("article",md,autoload=True)
classment(Base):__table__=Table("ment",md,autoload=True)Flask框架本身集成了對(duì)SQLAlchemy地支持,使用下面地方式也同樣可以建立與數(shù)據(jù)庫地連接并且生成一個(gè)數(shù)據(jù)庫連接對(duì)象。定義模型fromflask_sqlalchemyimportSQLAlchemyfromsqlalchemyimportTable,MetaData
frommainimportapp#從main.py入口模板導(dǎo)入app對(duì)象
#為了避免出現(xiàn)Nomodulenamed'MySQLdb'異常,將pymysql安裝為MySQLdbimportpymysqlpymysql.install_as_MySQLdb()
#使用Flask集成化方式建立與數(shù)據(jù)庫地連接,并返回連接對(duì)象#定義連接字符串并集成到Flask實(shí)例地配置項(xiàng)app.config['SQLALCHEMY_DATABASE_URI']='mysql://root:一二三四五六@localhost:三三零六/woniunote?charset=utf八'#如果設(shè)置成True(默認(rèn)情況),將會(huì)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年智能家居門窗系統(tǒng)安裝與售后服務(wù)合同3篇
- 浙江省麗水市(2024年-2025年小學(xué)六年級(jí)語文)統(tǒng)編版摸底考試(下學(xué)期)試卷及答案
- 福建省莆田市(2024年-2025年小學(xué)六年級(jí)語文)統(tǒng)編版小升初真題(上學(xué)期)試卷及答案
- 繁榮文化消費(fèi)的創(chuàng)新策略與實(shí)施路徑分析
- 廣西梧州市(2024年-2025年小學(xué)六年級(jí)語文)部編版小升初模擬(上學(xué)期)試卷及答案
- 二零二五年度市政基礎(chǔ)設(shè)施施工建設(shè)合同
- 二零二五年度城市綠化帶病蟲害防治合同3篇
- 2025年中國寵物貓行業(yè)市場(chǎng)現(xiàn)狀、前景分析研究報(bào)告(智研咨詢發(fā)布)
- 基因檢測(cè)與健康保險(xiǎn)
- 實(shí)驗(yàn)室安全教育課件
- 初中七年級(jí)數(shù)學(xué)運(yùn)算能力培養(yǎng)策略(課件)
- 北京市東城區(qū)2023-2024學(xué)年高二上學(xué)期期末考試+英語 含答案
- 服裝廠安全教育培訓(xùn)規(guī)章制度
- 車輛修理廠自查自糾整改方案及總結(jié)報(bào)告
- 2024版成人腦室外引流護(hù)理TCNAS 42─20241
- **鎮(zhèn)家庭醫(yī)生簽約服務(wù)績(jī)效分配方案
- 湖北省八校2025屆高二生物第一學(xué)期期末質(zhì)量檢測(cè)模擬試題含解析
- 四川省食品生產(chǎn)企業(yè)食品安全員理論考試題庫(含答案)
- 新能源發(fā)電技術(shù) 課件 第6章 地?zé)岚l(fā)電
評(píng)論
0/150
提交評(píng)論