日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Flask视图、模板、模型

發布時間:2023/12/20 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flask视图、模板、模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Day01

Flask前期了解:

為什么要使用框架:

web網站發展至今,特別是服務器端,涉及到的知識、內容,非常廣泛。這對程序員的要求會越來越高。如果采用成熟,穩健的框架,那么一些基礎的工作,比如,網絡操作、數據庫訪問、會話管理等都可以讓框架來處理,那么程序開發人員可以把精力放在具體的業務邏輯上面。使用Web框架開發Web應用程序可以降低開發難度,提高開發效率。 總結一句話:避免重復造輪子(wheel)。

Flask框架的誕生:

Flask誕生于2010年,是Armin ronacher(人名)用Python語言基于Werkzeug工具箱編寫的輕量級Web開發框架。它主要面向需求簡單的小應用。Flask本身相當于一個內核,其他幾乎所有的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login),都需要用第三方的擴展庫來實現。比如可以用Flask-extension加入ORM、窗體驗證工具,文件上傳、身份驗證等。Flask沒有默認使用的數據庫,你可以選擇MySQL,也可以用NoSQL。其 WSGI 工具箱采用 Werkzeug(路由模塊) ,模板引擎則使用 Jinja2 。Python最出名的框架要數Django,此外還有Flask、Tornado等框架。雖然Flask不是最出名的框架,但是Flask應該算是最靈活的框架之一,這也是Flask受到廣大開發者喜愛的原因。

基于python的web (微) 框架

重量級框架 django為了方便業務程序的開發,提供了豐富的工具及其組件 輕量級框架 flask只提供web核心功能,自由靈活,高度定制,用到什么就可以選擇什么樣的第三方庫來實現其功能;

官方文檔

http://flask.pocoo.org/docs/0.12/ 英文 http://docs.jinkan.org/docs/flask/ 中文

flask依賴庫

flask依賴的基礎的三個庫jinja2 模板引擎(就是可以用模板語法和html標簽結合生成想要的網頁源代碼)Werkzeug WSGI (web server gateway interface)工具集:Werkzeug 是一個 WSGI(在 Web 應用和多種服務器之間的標準 Python 接口) 工具集Itsdangerous 基于Django的簽名模塊現在不僅僅是三個 但是依然前兩個有用安裝時候會出現6個 看看就可以了

flask流行的主要原因

1 有非常齊全的官方文檔,上手非常方便2 有非常好的擴展機制和第三方擴展環境,工作中常見的軟件都會有對應的擴展,動手實現擴展也很容易3 社區活躍度非常高 flask的熱度已經超過django好幾百了4 微型框架的形式給了開發者更大的選擇空間

MVC簡介:

MVC的全拼為Model-View-Controller,最早由TrygveReenskaug在1978年提出,是施樂帕羅奧多研究中心(Xerox PARC)在20世紀80年代為程序語言Smalltalk發明的一種軟件設計模式,是為了將傳統的輸入(input)、處理(processing)、輸出(output)任務運用到圖形化用戶交互模型中而設計的。隨著標準輸入輸出設備的出現,開發人員只需要將精力集中在業務邏輯的分析與實現上。后來被推薦為Oracle旗下Sun公司Java EE平臺的設計模式,并且受到越來越多的使用ColdFusion和PHP的開發者的歡迎。現在雖然不再使用原來的分工方式,但是這種分工的思想被沿用下來,廣泛應用于軟件工程中,是一種典型并且應用廣泛的軟件架構模式。后來,MVC的思想被應用在了Web開發方面,被稱為Web MVC框架。MVC框架的核心思想是:解耦,讓不同的代碼塊之間降低耦合,增強代碼的可擴展性和可移植性,實現向后兼容。當前主流的開發語言如Java、PHP、Python中都有MVC框架。Web MVC各部分的功能 M:全拼為Model,主要封裝對數據庫層的訪問,對數據庫中的數據進行增、刪、改、查操作。V:全拼為View,用于封裝結果,生成頁面展示的html內容。C:全拼為Controller,用于接收請求,處理業務邏輯,與Model和View交互,返回結果。

MVC的處理邏輯圖:

概括性總結MVC:

一種軟件設計架構風范 Model數據的封裝,數據的抽象,用來操作數據的入口 View視圖,主要用來呈現給用戶的 Controller控制器,主要用來接收用戶請求(輸入),并且協調模型和視圖用來做視圖和模型之間的數據的交互 核心理念解耦 實現結果將數據操作,頁面展示,邏輯處理進行了拆分

MTV也叫做MVT

Models封裝數據操作數據庫的表和字段的定義 Template模板用來展示數據 Views視圖函數相當于controller接收請求,協調模型和模板

MTV的處理邏輯圖:

Flask基本準備使用前的工作:

創建Flask的虛擬環境:

在開發中每個項目都有自己的獨立環境,所以需要virtualenv創建環境 一般公司的開發都在ubuntu下,所以安裝如下: 1. $ sudo apt install virtualenv sudo apt install python-pip 注意:如果沒有apt 那么解決辦法 sudo apt update 更新源中的軟件包包管理工具apt update 更新源中的軟件包apt install xxx 安裝指定的軟件xxxapt remove xxx 卸載軟件(僅僅卸載軟件)apt autoremove xxx 卸載軟件(會卸載軟件和沒有用的依賴包) 接著下載virtualenv的管理工具: 2. sudo pip install virtualenvwrapper 注意有丟包的問題 virtualenvwrapper.sh安裝路徑/usr/local/bin/ 編輯bashrc文件 3. sudo vim ~/.bashrc 4.打開之后,進行下面編輯: #python export WORKON_HOME = /home/xxx(用戶名字)/.virtualenvs 5 注意需要創建.virtualenv的文件夾 mkdir $HOME/.virtualenvs 用來存放虛擬環境 source xxx(virtualenvwrapper.sh安裝路徑) virtualenvwrapper.sh 激活路徑 例如: #python export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 就是每次創建的虛擬環境都是依靠python3的 export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh6 激活創建后后的環境變量 source .bashrc 7 創建3.x的虛擬環境 mkvirtualenv xxx(虛擬環境的名字) -p /usr/bin/python3 退出虛擬環境 deactivate 進入虛擬環境 workon ENV_NAME(虛擬環境的名字) 查詢路徑 whereis python3對于pip管理python包的操作: pip install xxx 安裝某一個軟件pip uninstall xxx 卸載某一個軟件pip list 列出所有的依賴包pip freeze 列出自己安裝的所有的依賴包

web網站的工作方式(http的請求方式):

Flask開始正文:

創建flask的虛擬環境mkvirtualenv Flaskpython1901 -p /usr/bin/python3 查看虛擬環境pip freezepip list虛擬環境遷移pip freeze > requirements.txt遷出pip install -r requirements.txt遷入 安裝pip install flask 創建項目mkdir python1901 mkdir Flaskday01 mkdir FirstFlask vim HelloFlask.py代碼結構from flask import Flask# 創建flask應用的對象,__name__如果以當前文件作為啟動文件那么__name__值是__main__,如果不是啟動文件那么它值的就是當前模塊的名字。app = Flask(__name__)@app.route("/index/")def index():return "helloflask"if __name__ == "__main__":app.run()啟動服務器 python 文件名字.py默認端口號 5000 只允許本機鏈接如果想修改端口號那么可以在run方法中添加參數在啟動的時候可以添加參數 在run()中debug是否開啟調試模式,開啟后修改過python代碼自動重啟如果修改的是html/js/css 那么不會自動重啟host主機,默認是127.0.0.1 指定為0.0.0.0代表本機ipport指定服務器端口號threaded是否開啟多線程 # 修改服務器端口號 可以在run方法中添加port屬性# 注意 注意port的數據類型 可以是整型 可以是字符串# app.run(port=8888)# 注意 默認情況下只允許本機訪問 可以修改run方法中的host屬性值為0.0.0.0# app.run(port='8888',host='0.0.0.0')# 默認情況下 修改python代碼必須要重啟服務器# 如果不想重啟服務器 那么需要加一個debug參數# 注意的是 修改python代碼 可以通過保存重啟服務器 那么如果是html css js等前端# 代碼 那么就必須重啟服務器# app.run(port='8888',debug=True,threaded=True)PIN碼全稱Personal Identification Number.就是SIM卡的個人識別密碼。手機的PIN碼是保護SIM卡的一種安全措施,防止別人盜用SIM卡,如果啟用了開機PIN碼,那么每次開機后就要輸入4到8位數PIN碼。 在輸入三次PIN碼錯誤時,手機便會自動鎖卡,并提示輸入PUK碼解鎖,需要使用服務密碼撥打運營商客服熱線,客服會告知初始的PUK碼,輸入PUK碼之后就會解鎖PIN碼。

Flask的腳本命令行參數:

命令行參數:作用就是可以在啟動程序的時候進行修改主機ip和端口號等等。1.安裝pip install flask-script如果安裝的慢可以用豆瓣源進行安裝:pip install flask-script -i https://pypi.douban.com/simple作用啟動命令行參數可以在腳本中添加自己喜歡的參數;2.初始化修改 app.py文件為manager.py3.將app對象交給manager來管理(和Django很相似)注意:Ctrl + Alt + Space 快速導入任意類 或者 倒包的快捷鍵 ctrl + space/alter + entermanager = Manager(app=app)修改 文件.run()為manager.run()4.運行python manager.py runserver -p xxx -h xxxx -d -r參數注意:不可以大寫。- p 端口 port- h 主機 host- d 調試模式 debug- r 重啟(重新加載) reload(restart)基本使用:index返回字符串@app.route('/index/')def index():return 'index'模板first.html@app.route('/first/')def hello():return render_template("test.html")返回值的類型類也是字符串;靜態文件css注意<link rel="stylesheet" href="/static/css/hello.css">對于開始啟動項目會出現以下錯誤狀態碼:404 路徑錯誤405 請求方式錯誤500 服務器錯誤302 重定向301 永久重定向

Flask的簡單運行過程:

所有Flask程序必須有一個程序實例。Flask調用視圖函數后,會將視圖函數的返回值作為響應的內容,返回給客戶端。一般情況下,響應內容主要是字符串和狀態碼。當客戶端想要獲取資源時,一般會通過瀏覽器發起HTTP請求。此時,Web服務器使用WSGI(Web Server Gateway Interface)協議,把來自客戶端的所有請求都交給Flask程序實例。WSGI是為 Python 語言定義的Web服務器和Web應用程序之間的一種簡單而通用的接口,它封裝了接受HTTP請求、解析HTTP請求、發送HTTP,響應等等的這些底層的代碼和操作,使開發者可以高效的編寫Web應用。程序實例使用Werkzeug來做路由分發(URL請求和視圖函數之間的對應關系)。根據每個URL請求,找到具體的視圖函數。 在Flask程序中,路由的實現一般是通過程序實例的route裝飾器實現。route裝飾器內部會調用add_url_route()方法實現路由注冊。調用視圖函數,獲取響應數據后,把數據傳入HTML模板文件中,模板引擎負責渲染響應數據,然后由Flask返回響應數據給瀏覽器,最后瀏覽器處理返回的結果顯示給客戶端。

Flask基礎結構

項目Apptemplates模板默認也需要和項目保持一致static靜態資源默認需要和我們的項目保持一致,在一個路徑中,指的Flask對象創建的路徑viewsmodels坑點一:起初視圖函數是在manager.py文件中,如果把視圖函數改到views.py文件中那么再執行過程中manager.py和其他的文件的惠出現找不到路徑的問題。出現如下: Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again 后臺回報出404錯誤;第二個坑--封裝__init__文件-- 在注冊藍圖之前,將app對象的初始化在__init__.py文件中,從而進行封裝。 from flask import Flask def create_app():app = Flask(__name__)return app 之后在manager.py輸入: from App import create_app app = create_app()

路由分發機制:

在flask中路由分發 1、如果路由名字后面沒有寫/ 那么請求的路徑后面就不可以寫/ 2、如果路由名字后面寫了/ 那么請求的路徑后面怎么寫都可以 # 所以在route()中路由名字一般情況下 /路由名字/ @app.route('/index/') # 路由的名字和視圖函數的名字 一般情況下一致,這個是開發的經驗; def index():return 'index'

對于解決路由路徑:

1、在注冊之前在__init__.py中進行app對象的初始化; from flask import Flask def create_app():app = Flask(__name__)return app 之后在manager.py輸入: from App import create_app app = create_app() 2、藍圖1. 宏偉藍圖(宏觀規劃)2. 藍圖也是一種規劃,主要用來規劃urls(路由)3. 藍圖基本使用- 安裝- pip install flask-blueprint- 初始化藍圖 blue = Blueprint('first',__name__)需要在view視圖函數中進行初始化;- 調用藍圖進行路由注冊 app.register_blueprint(blueprint=blue)代碼: views文件中: from flask import Blueprint # 初始化藍圖 blue = Blueprint('first',__name__) @blue.route("/") def hello_world():return "Hello"manager文件中: from App.views import blue # 注冊藍圖 app.register_blueprint(blueprint=blue)

視圖函數:

# 使用藍圖的坑 藍圖對象的創建和使用必須都要在views里 @app.route('/helloint/') def helloint():# 視圖函數的返回值類型 必須是一個字符串 元祖 response實例對象 不能是一個整數# return 1return 'this is return value'# 執行一個視圖函數 返回的是一個頁面 @app.route('/hellotemplate/') def hellotemplate():# 跳轉到一個頁面# return render_template('hellotemplate.html') # 從數據庫中將查詢到的數據 方到頁面中name = '本夕'return render_template('hellotemplate.html',name=name) 一般括號中的變量的命名與函數中變量是同名,開發經驗而已,然而在模板中接收的鍵(也就是括號中的變量參數)引用模板文件: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> {# link鏈接最低需要 rel、href屬性 script鏈接最低需要 type、src屬性#}<link rel="stylesheet" href="/static/css/hellotemplate.css"> </head> <body> {# ul>li*5 按table鍵#}<ul><li>許嵩</li><li>汪蘇瀧</li><li>徐良</li><li>星弟</li><li>小賤</li></ul> <!--老板說了 這需要睡3秒 如果尾款收到了那么就將此行代碼刪除--> {# 修改了頁面中的html css js ...需要重啟服務器#}<h3>{{ name }}</h3> </body> </html>

瀏覽器帶參數請求:

帶參數的請求從客戶端或者瀏覽器發過來的請求帶參數@blue.route('/getstudents/<id>/')def getstudents(id):return '學生%s'+id路由中包含路徑參數語法<converter:var_name>書寫的converter可以省略,默認類型就是stringconverterstring接收的時候也是str, 匹配到 / 的時候是匹配結束@blue.route('/getperson/<string:name>/')def getperson(name):print(name)print(type(name))return namepath接收的時候也是str, / 只會當作字符串中的一個字符處理,并且返回getperson1后面的所有string類型的參數;@blue.route('/getperson1/<path:name>/')def getperson1(name):print(name)print(type(name))return nameint@blue.route('/makemoney/<int:money>/')def makemoney(money):print(type(money))return '1'float參數寫的時候必須是一個float數;@blue.route('/makemoneyfloat/<float:money>/')def makemoney(money):print(type(money))return '1'uuiduuid 類型,一種格式@blue.route(('/getuu/'))def getuu():uu = uuid.uuid4()print(uu)return str(uu)------------------------------------@blue.route('/getuuid/<uuid:uuid>/')def getuuid(uuid):print(uuid)print(type(uuid))return '2'any任意一個已提供選項的任意一個 而不能寫參數外的內容 注意的是參數必須是字符串 如果不加雙引號,必須是字符,不可以寫整數 ,注意/必須寫@blue.route('/getany/<any(a,b):p>/')def getany(p):return '1'請求方式postman一種模擬請求工具方法參數中添加methods=['GET','POST']安裝https://blog.csdn.net/Shyllin/article/details/802577551. 默認支持GET,HEAD,OPTIONS2. 如果想支持某一請求方式,需要自己手動指定3. 在route方法中,使用methods=["GET","POST","PUT","DELETE"]應該都是大寫,因為在前后端分離中要求大小寫的區別;

簡易的注冊跳轉頁面:

# 視圖函數的設置 # 執行一個視圖函數 然后跳轉到注冊頁面 # 輸入用戶名字 密碼 然后點擊注冊 執行一個請求 然后輸出注冊成功 @blue.route('/toregister/') def toregister():return render_template('register.html') # 默認flask中允許使用get options head請求方式 不允許使用post請求方式 # methods允許訪問的請求方式 # 如果定義了methods 那么默認的請求方式將失效 # mothods常用的有5中 post get patch put delete @blue.route('/register/',methods=['POST','Get']) def register():return '注冊成功'#模板設置 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> {#get 請求 參數是顯示到瀏覽器的地址路徑上的 不安全post 請求 參數不會顯示get請求參數的數據量 相對于比較 大概2k左右post 參數的數據量 相對于比較大表單默認請求方式是get #}<form action="/register/" method="get">name:<input type="text" name="name" placeholder="請輸入用戶名字"><br>password:<input type="password" name="password" placeholder="請輸入密碼"><br><input type="submit" value="提交"> </form> </body> </html>

反向解析:

反向解析,常用在模板中:獲取請求資源路徑url_for(藍圖的名字.方法名字)@blue.route("/heheheheheheheheheehhehe/", methods=["GET","POST","PUT"])def hehe():return "呵呵噠"@blue.route("/gethehe/")def get_hehe():p = url_for("first.hehe")return p 應用: views文件中 # 反向解析的應用 # 執行一個路由 跳轉到登錄頁面 然后點擊登錄 返回歡迎光臨 @blue.route('/tologin/') def tologin():return render_template('login.html') @blue.route('/login/',methods=['get','post']) def login():return '歡迎光臨紅浪漫'模板: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><form action="{{ url_for('blue.login') }}" method="post">name:<input type="text" name="name" placeholder="please input your name"><br>pass:<input type="password" name="password" placeholder="please input your password"><br><button>提交</button></form> </body> </html>

request

request是一個Python中請求的內置對象 內置對象:不需要創建就可以直接使用的對象 屬性1.method **請求方法2.base_url去掉get參數的url3.host_url只有主機和端口號的url4.url完整的請求地址5.remote_addr **請求的客戶端地址6.args **- get請求參數的包裝,args是一個ImmutableMultiDict對象,類字典結構對象- 數據存儲也是key-value- 最外層是元組,次外層是大列表,列表中的元素是元組,元組中左邊是key,右邊是 value如:ImmutableMultiDict([('name', 'zhanshang'), ('name', 'wangwu')])7.form **- 存儲結構和args一致- 默認是接收post參數- 還可以接收 PUT,PATCH參數8.files ** form標簽中有一個參數 enctype=maltipart/form-data 請求方式必須是post 使用files接 收文件上傳9.headers 請求頭10.path路由中的路徑11.cookies請求中的cookie12.session 與request類似,也是一個內置對象,可以直接打印 print(session)

代碼:

# request對象的屬性 @blue.route('/testrequest/',methods=['get','post']) def testrequest():# 獲取請求的方式print(request.method)print(request.base_url)print(request.host_url)print(request.url)print(request.path)# 反扒print(request.remote_addr)# request.args.get方法的作用是獲取get請求方式的參數# 如果參數中 有2個或者2個以上的參數名字一致那么只是返回第一個符合條件的參數值# 如果想獲取所有的參數值 那么調用的方法是getlist getlist方法的返回值類型是列表print(request.args.get('name'))print(request.args.getlist('name'))# post請求方式 如何獲取請求參數print(request.form.get('name'))print(request.form.get('age'))print(request.headers)return 'testrequest'@blue.route('/upload/', methods=['GET', 'POST']) def upload_file():if request.method == 'POST':f = request.files['the_file']f.save('/var/www/uploads/uploaded_file.txt')如果你想知道上傳前文件在客戶端的文件名是什么,你可以訪問 filename 屬性。但請記住, 永遠不要信任這個值,這個值是可以偽造的。如果你要把文件按客戶端提供的文件名存儲在服務器上,那么請把它傳遞給 Werkzeug 提供的 secure_filename() 函數: from flask import request from werkzeug import secure_filename @blue.route('/upload', methods=['GET', 'POST']) def upload_file():if request.method == 'POST':f = request.files['the_file']f.save('/var/www/uploads/' + secure_filename(f.filename))

Response

對于視圖函數Response的返回類型,有如下幾種方式: 字符串、元組、response。 1、返回的值為字符串類型:如果只是單一的返回字符串,就是返回內容或者數據,在return返回值中還可以有第二個返回,就是放的是狀態碼@blue.route('/response/')def get_response():return '德瑪西亞',404render_template 函數渲染模板將模板變成字符串,返回給瀏覽器; @blue.route('/rendertemplate/')def render_temp():resp = render_template('Response.html')print(resp)print(type(resp))return rese,5002、返回response類型:make_response函數Response對象返回內容狀態碼@blue.route('/makeresponse/')def make_resp():resp = make_response('<h2>xxxxxxxx</h2>',502)print(resp)print(type(resp))return reseredirect函數重定向@blue.route('/redirect/')def make_redir():return redirect('/makeresponse/')重定向結合反向解析 url_for@blue.route('/redirect/')def make_redir():return redirect(url_for('first.make_resp'))Response()函數

代碼:

# response 1、返回字符串類型: # return 返回的是字符串 @blue.route('/testresponse/') def testresponse():return 'testresponse',500# render_template方法返回值類型也是一個字符串 @blue.route('/testresponse1/') def testresponse1():res = render_template('index.html')print(res)print(type(res))return res2、返回response類型: # return后面也可以返回一個response類型的對象 # make_response方法返回的是response類型的對象 @blue.route('/testresponse2/') def testresponse2():res = make_response('<h1>哈哈</h1>')print(type(res))return res@blue.route('/testresponse3/') def testresponse3():# redirect# 重定向的方法的返回值類型是response對象res = redirect(url_for('blue.testresponse2'))print(type(res))return res@blue.route('/testresponse4/') def testresponse4():res = Response('呵呵')print(type(res))return res

異常

abort拋出異常:直接拋出 顯示錯誤狀態碼 終止程序運行abort(404)eg:@blue.route('/makeabort/')def make_abort():abort(404/502)return '天還行'捕獲異常:@blue.errorhandler()- 異常捕獲- 可以根據狀態或 Exception進行捕獲- 函數中要包含一個參數,參數用來接收異常信息eg:@blue.errorhandler(502)def handler502(exception):return '不能讓你看到狀態碼'代碼: # 異常 @blue.route('/testabort/') def testabort():abort(404)return 'testabort'# errorhandler參數必須是拋出的狀態碼 如果沒有拋出將不會執行 @blue.errorhandler(404) # 注意函數必須有一個參數 該參數是exception def testhandler(exception):return '沒問題'

會話技術

1.請求過程Request開始,到Response結束 2.連接都是短連接 3.延長交互的生命周期 4.將關鍵數據記錄下來 5.Cookie是保存在瀏覽器端/客戶端的狀態管理技術 6.Session是服務器端的狀態管理技術

會話機制流程圖:

cookie

Cookie1.客戶端會話技術2.所有數據存儲在客戶端3.以key-value進行數據存儲層4.服務器不做任何存儲5.特性支持過期時間max_ageexpries根據域名進行cookie存儲不能跨網站(域名)不能跨瀏覽器自動攜帶本網站的所有cookie6.cookie是服務器操作客戶端的數據7.通過Response進行操作cookie登陸使用設置cookie response.set_cookie('username',username)response獲取cookie username = request.cookies.get('username','游客')request刪除cookie response.delete_cookie('username')response代碼: # @blue.route('/tologincookie/') # def tologincookie(): # return render_template('logincookie.html') # # # @blue.route('/logincookie/',methods=['get','post']) # def logincookie(): # # 獲取post請求的參數的值 # # get方法里面應該寫的是標簽的name屬性值 # # 標簽的name屬性值 是 <input type='text' name='name'> # # 如果后端想獲取前端頁面的屬性值 那么get方法中就應該寫 標簽的name的值 # name = request.form.get('name') # # # redirect方法的返回值類型就是repsonse對象 # response = redirect(url_for('blue.toindexcookie')) # # response.set_cookie('name',name) # # return response # # # 跳轉到indexcookie.html # @blue.route('/toindexcookie/') # def toindexcookie(): # return render_template('indexcookie.html')# 先創建一個登錄頁面 # 在登錄頁面中輸入用戶名字 # 點擊登錄 # 跳轉到indexcookie.html # 該頁面中 有一句話 歡迎xxx來到紅浪漫洗浴 @blue.route('/tologincookie/') def tologincookie():return render_template('logincookie.html')@blue.route('/logincookie/',methods = ['get','post']) def logincookie():# 獲取的文本框中的內容name = request.form.get('name')# 反向解析 獲取的是路由地址 redirect是執行另一個路由# url_for(‘blue.indexcookie’)===>/indexcookie/# redirect('/indexcookie/')response = redirect(url_for('blue.indexcookie'))# 將name存儲到了cookie上response.set_cookie('name',name)return response# 跳轉到index頁面 @blue.route('/indexcookie/') def indexcookie():# 獲取cookie中的namename = request.cookies.get('name','游客')return render_template('indexcookie.html',name=name)@blue.route('/logoutcookie/') def logoutcookie():response = redirect(url_for('blue.indexcookie'))response.delete_cookie('name')return response模板: logincookie.html <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> {#提交要觸發的是form表單中action的值#} {#{{ url_for('blue.logincookie') }} 是反向解析 反向解析的結果是路由路徑 阿#}<form action="{{ url_for('blue.logincookie') }}" method="post">name:<input type="text" name="name" placeholder="please input your name"><br><button>提交</button></form> </body> </html>indexcookie.html <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>歡迎{{ name }}來到紅浪漫,拖鞋手牌拿好,樓上二樓左拐。。。。<br><a href="{{ url_for('blue.logoutcookie') }}">退出</a> </body> </html>

session

Session1.服務端會話技術2.所有數據存儲在服務器中3.默認存在服務器的內存中- django默認做了數據持久化(存在了數據庫中)4.存儲結構也是key-value形勢,鍵值對【注】單純的使用session是會報錯的,需要使用在__init__方法中配置app.config['SECRET_KEY']='110'# session緩存的位置app.config['SESSION_TYPE']='redis'app.config['SESSION_KEY_PREFIX'] = 'python1901'Session(app=app)# session = Session()# session.init_app(app=app)# No module named 'redis' 沒有redis的模塊 需要pip install redis

session的使用步驟:

flask-session使用步驟:1 pip install flask-session2 app.config['SESSION_TYPE']='redis'3 Session(app=app)/session = Session() session.init_app(app=app)查看redis keys *查看session生命周期 ttl sessionsession登陸使用設置 session['username'] = username獲取 session.get('username')刪除response.delete_cookie('session')session.pop('username')代碼: # seesion @blue.route('/tologinsession/') def tologinsession():return render_template('loginsession.html')@blue.route('/loginsession/',methods = ['get','post']) def loginsession():# 獲取的文本框中的內容name = request.form.get('name')# 反向解析 獲取的是路由地址 redirect是執行另一個路由# url_for(‘blue.indexcookie’)===>/indexcookie/# redirect('/indexcookie/')response = redirect(url_for('blue.indexsession'))# 將name存儲到了cookie上session['name'] = namereturn response# 跳轉到index頁面 @blue.route('/indexsession/') def indexsession():# 獲取cookie中的namename = session.get('name','游客')return render_template('indexsession.html',name=name)@blue.route('/logoutsession/') def logoutsession():response = redirect(url_for('blue.indexsession'))session.pop('name')return responseloginsession.html <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> {#提交要觸發的是form表單中action的值#} {#{{ url_for('blue.logincookie') }} 是反向解析 反向解析的結果是路由路徑 阿#}<form action="{{ url_for('blue.loginsession') }}" method="post">name:<input type="text" name="name" placeholder="please input your name"><br><button>提交</button></form> </body> </html>indexsession.html <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>歡迎{{ name }}來到紅浪漫,拖鞋手牌拿好,樓上二樓左拐。。。。<br><a href="{{ url_for('blue.logoutcookie') }}">退出</a> </body> </html>

session持久化問題

Session- django中對session做了持久化,存儲在數據庫中- 可以修改到redis中flask中沒有對默認session進行任何處理- flask-session 可以實現session的數據持久化- 各種位置,更推薦使用redis- 緩存在磁盤上的時候,管理磁盤文件使用lru, 最近最少使用原則服務端會話技術Flask中沒有對默認Session進行處理,默認存在內存中Session需要持久化 Redis中實現方案插件 flask-sessionpip install flask-session在國內源安裝pip install flask-sessin -i https://pipy.douban.com/simple初始化Session對象 配置init中app.config['SESSION_TYPE'] = 'redis'持久化的位置初始化創建session的對象有2中方式 分別是以下兩種1 Session(app=app)2 se = Session() se.init_app(app = app)安裝redispip install redis需要配置SECRET_KEY='110'其他配置--視情況而定app.config['SESSION_KEY_PREFIX']='flask'查看redis內容redis-clikeys *get keysession生存時間31天 ttl sessionflask的session的生存時間是31天,django的session生存時間是15天

Template模板:

在前面的示例中,視圖函數的主要作用是生成請求的響應,這是最簡單的請求。實際上,視圖函數有兩個作用:處理業務邏輯和返回響應內容。在大型應用中,把業務邏輯和表現內容放在一起,會增加代碼的復雜度和維護成本。本節學到的模板,它的作用即是承擔視圖函數的另一個作用,即返回響應內容。 模板其實是一個包含響應文本的文件,其中用占位符(變量)表示動態部分,告訴模板引擎其具體值需要從使用的數據中獲取。使用真實值替換變量,再返回最終得到的字符串,這個過程稱為“渲染”。Flask使用Jinja2這個模板引擎來渲染模板。Jinja2能識別所有類型的變量,包括{}。 Jinja2模板引擎,Flask提供的render_template函數封裝了該模板引擎,render_template函數的第一個參數是模板的文件名,后面的參數都是鍵值對,表示模板中變量對應的真實值。

Jinja2官方文檔(http://docs.jinkan.org/docs/jinja2/)

變量

在模板中{{ variable }}結構表示變量,是一種特殊的占位符,告訴模板引擎這個位置的值,在渲染模板時從視圖函數中獲取數據;Jinja2除了能識別基本類型的變量,還能識別{};

<p>{{mydict['key']}}</p> <p>{{mylist[1]}}</p> <p>{{mylist[myintvar]}}</p>from flask import Blueprint, render_template blue = Blueprint('blue',__name__) @blue.route('/') def index():mydict = {'key':'silence is gold'}mylist = ['Speech', 'is','silver']myintvar = 0return render_template('vars.html',mydict=mydict,mylist=mylist,myintvar=myintvar)

反向路由:

Flask提供了url_for()輔助函數,可以使用程序URL映射中保存的信息生成URL;url_for()接收視圖函數名作為參數,返回對應的URL;

如調用url_for(‘index’,_external=True)返回的是絕對地址,在下面這個示例中是http://127.0.0.1:5000/index。

@app.route('/index') def index():return render_template('index.html')@app.route('/user/') def redirect():return url_for('index',_external=True)

過濾器

過濾器的本質就是函數。有時候我們不僅僅只是需要輸出變量的值,我們還需要修改變量的顯示,甚至格式化、運算等等,這就用到了過濾器。 過濾器的使用方式為:變量名 | 過濾器。 過濾器名寫在變量名后面,中間用 | 分隔。如:{{variable | capitalize}},這個過濾器的作用:把變量variable的值的首字母轉換為大寫,其他字母轉換為小寫。 其他常用過濾器如下:

字符串操作:

safe:禁用轉義;

<p>{{ '<em>hello</em>' | safe }}</p>

capitalize:把變量值的首字母轉成大寫,其余字母轉小寫;

<p>{{ 'hello' | capitalize }}</p>

lower:把值轉成小寫;

<p>{{ 'HELLO' | lower }}</p>

upper:把值轉成大寫;

<p>{{ 'hello' | upper }}</p>

title:把值中的每個單詞的首字母都轉成大寫;

<p>{{ 'hello' | title }}</p>

trim:把值的首尾空格去掉;

<p>{{ ' hello world ' | trim }}</p>

reverse:字符串反轉;

<p>{{ 'olleh' | reverse }}</p>

format:格式化輸出;

<p>{{ '%s is %d' | format('name',17) }}</p>

striptags:渲染之前把值中所有的HTML標簽都刪掉;

<p>{{ '<em>hello</em>' | striptags }}</p>

列表操作

first:取第一個元素

<p>{{ [1,2,3,4,5,6] | first }}</p>

last:取最后一個元素

<p>{{ [1,2,3,4,5,6] | last }}</p>

length:獲取列表長度

<p>{{ [1,2,3,4,5,6] | length }}</p>

sum:列表求和

<p>{{ [1,2,3,4,5,6] | sum }}</p>

sort:列表排序

<p>{{ [6,2,3,1,5,4] | sort }}</p>

語句塊過濾(不常用):

{% filter upper %}this is a Flask Jinja2 introduction{% endfilter %}

自定義過濾器:

過濾器的本質是函數。當模板內置的過濾器不能滿足需求,可以自定義過濾器。自定義過濾器有兩種實現方式:一種是通過Flask應用對象的add_template_filter方法。還可以通過裝飾器來實現自定義過濾器。

自定義的過濾器名稱如果和內置的過濾器重名,會覆蓋內置的過濾器。

實現方式一:通過調用應用程序實例的add_template_filter方法實現自定義過濾器。該方法第一個參數是函數名,第二個參數是自定義的過濾器名稱。

def filter_double_sort(ls):return ls[::2] app.add_template_filter(filter_double_sort,'double_2')

實現方式二:用裝飾器來實現自定義過濾器。裝飾器傳入的參數是自定義的過濾器名稱。

@app.template_filter('db3') def filter_double_sort(ls):return ls[::-3]

Web表單:

web表單是web應用程序的基本功能。

它是HTML頁面中負責數據采集的部件。表單有三個部分組成:表單標簽、表單域、表單按鈕。表單允許用戶輸入數據,負責HTML頁面數據采集,通過表單將用戶輸入的數據提交給服務器。

在Flask中,為了處理web表單,我們一般使用Flask-WTF擴展,它封裝了WTForms,并且它有驗證表單數據的功能。

WTForms支持的HTML標準字段

字段對象 說明
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密碼文本字段
HiddenField 隱藏文本字段
DateField 文本字段,值為datetime.date格式
DateTimeField 文本字段,值為datetime.datetime格式
IntegerField 文本字段,值為整數
DecimalField 文本字段,值為decimal.Decimal
FloatField 文本字段,值為浮點數
BooleanField 復選框,值為True和False
RadioField 一組單選框
SelectField 下拉列表
SelectMultipleField 下拉列表,可選擇多個值
FileField 文本上傳字段
SubmitField 表單提交按鈕
FormField 把表單作為字段嵌入另一個表單
FieldList 一組指定類型的字段

WTForms常用驗證函數

驗證函數 說明
DataRequired 確保字段中有數據
EqualTo 比較兩個字段的值,常用于比較兩次密碼輸入
Length 驗證輸入的字符串長度
NumberRange 驗證輸入的值在數字范圍內
URL 驗證URL
AnyOf 驗證輸入值在可選列表中
NoneOf 驗證輸入值不在可選列表中

使用Flask-WTF需要配置參數SECRET_KEY。

CSRF_ENABLED是為了CSRF(跨站請求偽造)保護。 SECRET_KEY用來生成加密令牌,當CSRF激活的時候,該設置會根據設置的密匙生成加密令牌。

在HTML頁面中直接寫form表單:

#模板文件 <form method='post'><input type="text" name="username" placeholder='Username'><input type="password" name="password" placeholder='password'><input type="submit"> </form>

視圖函數中獲取表單數據:

from flask import Flask,render_template,request@app.route('/login',methods=['GET','POST']) def login():if request.method == 'POST':username = request.form['username']password = request.form['password']print username,passwordreturn render_template('login.html',method=request.method)

使用Flask-WTF實現表單。

配置參數:

app.config['SECRET_KEY'] = 'silents is gold'

模板頁面:

<form method="post">#設置csrf_token{{ form.csrf_token() }}{{ form.us.label }}<p>{{ form.us }}</p>{{ form.ps.label }}<p>{{ form.ps }}</p>{{ form.ps2.label }}<p>{{ form.ps2 }}</p><p>{{ form.submit() }}</p>{% for x in get_flashed_messages() %}{{ x }}{% endfor %}</form>

視圖函數:

#coding=utf-8 from flask import Flask,render_template,\redirect,url_for,session,request,flash#導入wtf擴展的表單類 from flask_wtf import FlaskForm #導入自定義表單需要的字段 from wtforms import SubmitField,StringField,PasswordField #導入wtf擴展提供的表單驗證器 from wtforms.validators import DataRequired,EqualTo app = Flask(__name__) app.config['SECRET_KEY']='1'#自定義表單類,文本字段、密碼字段、提交按鈕 class Login(Form):us = StringField(label=u'用戶:',validators=[DataRequired()])ps = PasswordField(label=u'密碼',validators=[DataRequired(),EqualTo('ps2','err')])ps2 = PasswordField(label=u'確認密碼',validators=[DataRequired()])submit = SubmitField(u'提交')@app.route('/login') def login():return render_template('login.html')#定義根路由視圖函數,生成表單對象,獲取表單數據,進行表單數據驗證 @app.route('/',methods=['GET','POST']) def index():form = Login()if form.validate_on_submit():name = form.us.datapswd = form.ps.datapswd2 = form.ps2.dataprint name,pswd,pswd2return redirect(url_for('login'))else:if request.method=='POST':flash(u'信息有誤,請重新輸入!')print form.validate_on_submit()return render_template('index.html',form=form) if __name__ == '__main__':app.run(debug=True)

控制語句

常用的幾種控制語句:

模板中的if控制語句,模板中的for循環語句

# 列表的遍歷 @blue.route('/scorelist/') def scorelist():content = 'girl'scorelist1 = [100,90,80,70,60]content1 = '<h1>蔡徐坤</h1>'return render_template('scorelist.html',scorelist1=scorelist1,content=content,content1=content1)<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><ul>{% for s in scorelist1 %} {# {{ loop.index }}:{{ loop.index0 }}#}{% if loop.first %}<li style="color:#3cff3f;">{{ s }}</li>{% elif loop.last %}<li style="color:red;">{{ s }}</li>{% else %}<li style="color:blueviolet;">{{ s }}</li>{% endif %}{% endfor %}</ul>{{ content|upper|reverse }}{{ content1|safe }} </body> </html>

宏、繼承、包含

類似于python中的函數,宏的作用就是在模板中重復利用代碼,避免代碼冗余,然而Django的模板中沒有此定義。

Jinja2支持宏,還可以導入宏,需要在多處重復使用的模板代碼片段可以寫入單獨的文件,再包含在所有模板中,以避免重復。

定義宏

{% macro input() %}<input type="text"name="username"value=""size="30"/> {% endmacro %}

調用宏

{{ input() }}

定義帶參數的宏

{% macro input(name,value='',type='text',size=20) %}<input type="{{ type }}"name="{{ name }}"value="{{ value }}"size="{{ size }}"/> {% endmacro %}

調用宏,并傳遞參數

{{ input(value='name',type='password',size=40)}}

把宏單獨抽取出來,封裝成html文件,其它模板中導入使用

文件名可以自定義macro.html

{% macro function() %}<input type="text" name="username" placeholde="Username"><input type="password" name="password" placeholde="Password"><input type="submit"> {% endmacro %}

在其它模板文件中先導入,再調用

{% import 'macro.html' as func %} {% func.function() %}

模板繼承:

模板繼承是為了重用模板中的公共內容。一般Web開發中,繼承主要使用在網站的頂部菜單、底部。這些內容可以定義在父模板中,子模板直接繼承,而不需要重復書寫。

{% block top %}``{% endblock %}標簽定義的內容,相當于在父模板中挖個坑,當子模板繼承父模板時,可以進行填充。

子模板使用extends指令聲明這個模板繼承自哪?父模板中定義的塊在子模板中被重新定義,在子模板中調用父模板的內容可以使用super()。

父模板:base.html

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>瞎寫的</title> {#block結構標簽#}{% block ext_css %}{% endblock %} </head> <body>{% block header %}頭部{% endblock %}{% block content %}文本{% endblock %}{% block footer %}底部{% endblock %}{% block ext_js %}js代碼{% endblock %} </body> </html>

子模板繼承:

base_a.html

{% extends 'base.html' %}{% block footer %}為什么今天這么蒙。。。 渾渾噩噩 感覺好象沒洗澡 {% endblock %}{% block header %}蒼滿的天涯是我的愛 {% endblock %}{% block ext_js %}綿綿的青山腳下花正開 {% endblock %}{% block content %}什么歌聲最亞封疆大吏封疆大吏方 {% endblock %}

base_b.html

{% extends 'base_a.html' %}{% block header %}{{ super() }} 調用父類,防止被子類覆蓋;梁博 表態 {% endblock %}{% block footer %}{% include 'include.html' %} {% endblock %}

include.html

<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li> </ul>

模板繼承使用時注意點:

不支持多繼承。為了便于閱讀,在子模板中使用extends時,盡量寫在模板的第一行。不能在一個模板文件中定義多個相同名字的block標簽。當在頁面中使用多個block標簽時,建議給結束標簽起個名字,當多個block嵌套時,閱讀性更好。

包含(Include)

Jinja2模板中,除了宏和繼承,還支持一種代碼重用的功能,叫包含(Include)。它的功能是將另一個模板整個加載到當前模板中,并直接渲染。

示例:

include的使用結果看上面的代碼:

{\% include 'hello.html' %}

包含在使用時,如果包含的模板文件不存在時,程序會拋出TemplateNotFound異常,可以加上ignore missing關鍵字。如果包含的模板文件不存在,會忽略這條include語句。

示例:

include的使用加上關鍵字ignore missing

{\% include 'hello.html' ignore missing %}

宏、繼承、包含:

宏(Macro)、繼承(Block)、包含(include)均能實現代碼的復用。繼承(Block)的本質是代碼替換,一般用來實現多個頁面中重復不變的區域。宏(Macro)的功能類似函數,可以傳入參數,需要定義、調用。包含(include)是直接將目標模板文件整個渲染出來。

Flask中的特殊變量和方法:

在Flask中,有一些特殊的變量和方法是可以在模板文件中直接訪問的。

config 對象:

config 對象就是Flask的config對象,也就是 app.config 對象。{{ config.SQLALCHEMY_DATABASE_URI }}

request 對象:

就是 Flask 中表示當前請求的 request 對象,request對象中保存了一次HTTP請求的一切信息。

request常用的屬性如下:

屬性 說明 類型
data 記錄請求的數據,并轉換為字符串 *
form 記錄請求中的表單數據 MultiDict
args 記錄請求中的查詢參數 MultiDict
cookies 記錄請求中的cookie信息 Dict
headers 記錄請求中的報文頭 EnvironHeaders
method 記錄請求使用的HTTP方法 GET/POST
url 記錄請求的URL地址 string
files 記錄請求上傳的文件 *

{{ request.url }}

url_for 方法:

url_for() 會返回傳入的路由函數對應的URL,所謂路由函數就是被 app.route() 路由裝飾器裝飾的函數。如果我們定義的路由函數是帶有參數的,則可以將這些參數作為命名參數傳入。

{{ url_for('index') }}{{ url_for('post', post_id=1024) }}

get_flashed_messages方法:

返回之前在Flask中通過 flash() 傳入的信息列表。把字符串對象表示的消息加入到一個消息隊列中,然后通過調用 get_flashed_messages() 方法取出。

{% for message in get_flashed_messages() %}{{ message }} {% endfor %}

Models模型:

數據模型開發前的初始配置:

數據庫的設置

Web應用中普遍使用的是關系模型的數據庫,關系型數據庫把所有的數據都存儲在表中,表用來給應用的實體建模,表的列數是固定的,行數是可變的。它使用結構化的查詢語言。關系型數據庫的列定義了表中表示的實體的數據屬性。比如:商品表里有name、price、number等。 Flask本身不限定數據庫的選擇,你可以選擇SQL或NOSQL的任何一種。也可以選擇更方便的SQLALchemy,類似于Django的ORM。SQLALchemy實際上是對數據庫的抽象,讓開發者不用直接和SQL語句打交道,而是通過Python對象來操作數據庫,在舍棄一些性能開銷的同時,換來的是開發效率的較大提升。

SQLAlchemy是一個關系型數據庫框架,它提供了高層的ORM和底層的原生數據庫的操作。flask-sqlalchemy是一個簡化了SQLAlchemy操作的flask擴展。

1.數據交互的封裝 2.Flask默認并沒有提供任何數據庫操作的API,Flask中可以自己的選擇數據,用原生語句實現功能,但是原生SQL缺點:代碼利用率低,條件復雜代碼語句越過長,有很多相似語句;一些SQL是在業務邏輯中拼出來的,修改需要了解業務邏輯;也可以選擇ORM方便對數據的操作SQLAlchemyMongoEngine將對象的操作轉換為原生SQL優點:易用性,可以有效減少重復SQL;性能損耗少;設計靈活,可以輕松實現復雜查詢;移植性好; 3.Flask中并沒有提供默認ORM:ORM 對象關系映射通過操作對象,實現對數據的操作使用步驟:1.安裝pip install flask-sqlalchemy包2.在models文件中創建SQLALCHEMY對象db = SQLAlchemy()3.在init文件中進行配置: config中配置SQLALCHEMY_DATABASE_URI dialect+driver://username:password@host:port/database 數據庫 + 驅動 :// 用戶:密碼@ 主機:端口/數據庫 app.config['SQLALCHEMY_DATABASE_URI']='mysql+pymysql://root:1234@localhost:3306/flask1901' app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False 因為需要db來調用屬性 db.init_app(app=app) db.init_app(app=app)

代碼實現:

1 安裝sqlalchemy pip install flask-sqlalchemy 2 在models.py文件中創建SQLALCHEMY對象 # 模型的創建需要繼承 db.Model # 2個坑 + 1個大坑 # from App import db # db對象 如果放到了方法里,那么是不可以導入到其他模塊的 from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # User模型 應該對應著 表 # 模型的屬性應該對應表的字段 class User(db.Model):# flask中 模型必須有主鍵ser could not assemble any primary key columnsid = db.Column(db.Integer,primary_key=True,autoincrement=True)# (in table 'user', column 'name'): VARCHAR requires a length on dialect mysql# flask的模型中的字符串必須有長度name = db.Column(db.String(32))age = db.Column(db.Integer)3.在__init__.py文件進行配置: from flask import Flask from App.models import db def create_app():app = Flask(__name__)# 數據庫的鏈接路徑# dialect + driver: // username: password @ host:port / database# 方言 驅動 用戶名子 密碼 主機 3306 數據庫的名字app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:1234@localhost:3306/flask1901'# 當使用sqlalchemy的時候 啟動服務器會報錯# SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.# 在將來版本更新的過程中可能會遇到的錯誤# 如果還報錯 有2中情況 要么單詞打錯 要么放在了創建對象之后了app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falsedb.init_app(app=app)return app4.views.py文件中調用視圖函數: from flask import Blueprint from App import db blue = Blueprint('blue',__name__) # 創建一個模型,然后執行一個方法,就會生成相應的表 @blue.route('/createuser/') def createuser():db.create_all()return '創建成功'5.manager.py from flask_script import Manager from App import create_app from App.views import blue app = create_app() manager = Manager(app=app) app.register_blueprint(blueprint=blue) if __name__ == '__main__':manager.run()使用:定義模型:繼承Sqlalchemy對象中的model定義字段:主鍵一定要添加,所需要字段語法:db.Column( db.類型(),約束 )創建db.create_all()刪除db.drop_all()修改表名__tablename__ = "Worker"數據操作創建對象添加db.session.add(對象)db.session.commit()查詢模型.query.all()

項目拆分

項目拆分開發環境開發環境測試環境演示環境-類似線上環境也叫做預生產環境線上環境 也叫做 生產環境Flask輕量級框架,在一個文件中實現所有功能拆分項目MTV的樣子規劃項目結構manager.py程序入口app的創建Manager (flask-script管理對象)可以接收命令行參數App__init__創建Flask對象app加載settings文件調用init_ext方法調用init_blue方法settingsApp運行的環境配置運行環境ext(擴展的,額外的)用來初始化第三方的各種插件Sqlalchemy對象初始化 數據庫Session初始化views藍圖創建注冊到app上models定義模型__init__.py from flask import Flask from App import settings from App.ext import init_extdef create_app():app = Flask(__name__)# session# app.config['SECRET_KEY']='114'# app.config['SESSION_TYPE']='redis'# Session(app=app)# 建立與settings文件的關鍵# settings.ENV_NAME.get('develop')獲取的是settings文件中的value值# app.config.from_object(DevelopConfig)將類加載過來app.config.from_object(settings.ENV_NAME.get('develop'))# sqlalchemy# db.init_app(app=app)init_ext(app)return appext.py # 用來存放第三方擴展庫 from flask_session import Session from App.models import dbdef init_ext(app):app.config['SECRET_KEY']='114'app.config['SESSION_TYPE']='redis'Session(app=app)db.init_app(app=app)setting.py # 配置數據庫環境 def get_database_uri(DATABASE):dialect = DATABASE.get('dialect') or 'mysql'driver = DATABASE.get('driver') or 'pymysql'username = DATABASE.get('username') or 'root'password = DATABASE.get('password') or '1234'host = DATABASE.get('host') or 'localhost'port = DATABASE.get('port') or '3306'database = DATABASE.get('database') or 'flaskday03'# dialect+driver://username:password@host:port/databasereturn '{}+{}://{}:{}@{}:{}/{}'.format(dialect,driver,username,password,host,port,database)class Config():# 測試環境需要打開Test# 測試環境除外 需要打開DebugTest = FalseDebug = FalseSQLALCHEMY_TRACK_MODIFICATIONS = False# 每一套數據環境 都不一致 鏈接的是不同的數據庫 class DevelopConfig(Config):Debug = TrueDATABASE={'dialect':'mysql','driver':'pymysql','username':'root','password':'1234','host':'localhost','port':'3306','database':'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class TestConfig(Config):Test = TrueDATABASE = {'dialect': 'mysql','driver': 'pymysql','username': 'root','password': '1234','host': 'localhost','port': '3306','database': 'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class ShowConfig(Config):Debug = TrueDATABASE = {'dialect': 'mysql','driver': 'pymysql','username': 'root','password': '1234','host': 'localhost','port': '3306','database': 'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class ProductConfig(Config):Debug = TrueDATABASE = {'dialect': 'mysql','driver': 'pymysql','username': 'root','password': '1234','host': 'localhost','port': '3306','database': 'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)ENV_NAME = {'develop':DevelopConfig,'test':TestConfig,'show':ShowConfig,'product':ProductConfig }models.py from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Student(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)name = db.Column(db.String(32))views.py from flask import Blueprintfrom App.models import db, Studentblue = Blueprint('blue',__name__)@blue.route('/') def index():return 'index'@blue.route('/createstudent/') def createstudent():db.create_all()return 'ok'@blue.route('/savestudent/') def savestudent():s = Student()s.name = '小明'db.session.add(s)db.session.commit()return 'ok'manager.py from flask_script import Manager from App import create_app from App.views import blue app = create_app() manager = Manager(app=app) app.register_blueprint(blueprint=blue) if __name__ == '__main__':manager.run()

數據庫基本操作

在Flask-SQLAlchemy中,插入、修改、刪除操作,均由數據庫會話管理。會話用db.session表示。在準備把數據寫入數據庫前,要先將數據添加到會話中然后調用commit()方法提交會話。

數據庫會話是為了保證數據的一致性,避免因部分更新導致數據不一致。提交操作把會話對象全部寫入數據庫,如果寫入過程發生錯誤,整個會話都會失效。

數據庫會話也可以回滾,通過db.session.rollback()方法,實現會話提交數據前的狀態。

在Flask-SQLAlchemy中,查詢操作是通過query對象操作數據。最基本的查詢是返回表中所有數據,可以通過過濾器進行更精確的數據庫查詢。

DDL 數據定義語言 data ding language

專門用來操作表的 create drop alter

DML 數據操縱語言 data make language

專門用來操作記錄的 insert delete update

DQL 數據查詢語言

專門用來查詢記錄的 select

TCL 事務

commit roolback

將數據添加到會話中示例:

user = User(name='python') db.session.add(user) db.session.commit()

在視圖函數中定義模型類

from flask import Flask from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)#設置連接數據庫的URL app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'#設置每次請求結束后會自動提交數據庫中的改動 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = Trueapp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True #查詢時會顯示原始SQL語句 app.config['SQLALCHEMY_ECHO'] = True db = SQLAlchemy(app)class Role(db.Model):# 定義表名__tablename__ = 'roles'# 定義列對象id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(64), unique=True)us = db.relationship('User', backref='role')#repr()方法顯示一個可讀字符串def __repr__(self):return 'Role:%s'% self.nameclass User(db.Model):__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(64), unique=True, index=True)email = db.Column(db.String(64),unique=True)pswd = db.Column(db.String(64))role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))def __repr__(self):return 'User:%s'%self.name if __name__ == '__main__':db.drop_all()db.create_all()ro1 = Role(name='admin')ro2 = Role(name='user')db.session.add_all([ro1,ro2])db.session.commit()us1 = User(name='wang',email='wang@163.com',pswd='123456',role_id=ro1.id)us2 = User(name='zhang',email='zhang@189.com',pswd='201512',role_id=ro2.id)us3 = User(name='chen',email='chen@126.com',pswd='987654',role_id=ro2.id)us4 = User(name='zhou',email='zhou@163.com',pswd='456789',role_id=ro1.id)db.session.add_all([us1,us2,us3,us4])db.session.commit()app.run(debug=True)

DML模型操作

創建表:

db.create_all()

刪除表

db.drop_all()增db.session.add()將對象增加session中,然后用commit進行提交:@blue.route("/addperson/")def add_person():p = Person()p.p_name = "小明"p.p_age = 15db.session.add(p)db.session.commit()return "添加成功"db.session.add_all()eg:@blue.route("/addpersons/")def app_persons():persons = []for i in range(5):p = Person()p.p_name = "猴子請來的救兵%d" % random.randrange(100)p.p_age = random.randrange(70)persons.append(p)db.session.add_all(persons)db.session.commit()return "添加成功"# 插入一條數據 ro1 = Role(name='admin') db.session.add(ro1) db.session.commit() #再次插入一條數據 ro2 = Role(name='user') db.session.add(ro2) db.session.commit()# 一次插入多條數據 us1 = User(name='wang',email='wang@163.com',pswd='123456',role_id=ro1.id) us2 = User(name='zhang',email='zhang@189.com',pswd='201512',role_id=ro2.id) us3 = User(name='chen',email='chen@126.com',pswd='987654',role_id=ro2.id) us4 = User(name='zhou',email='zhou@163.com',pswd='456789',role_id=ro1.id) db.session.add_all([us1,us2,us3,us4]) db.session.commit()刪除db.session.delete(對象)基于查詢修改db.session.add(對象)基于查詢

常用的SQLAlchemy查詢過濾器

過濾器 說明
filter() 把過濾器添加到原查詢上,返回一個新查詢
filter_by() 把等值過濾器添加到原查詢上,返回一個新查詢
limit 使用指定的值限定原查詢返回的結果
offset() 偏移原查詢返回的結果,返回一個新查詢
order_by() 根據指定條件對原查詢結果進行排序,返回一個新查詢
group_by() 根據指定條件對原查詢結果進行分組,返回一個新查詢

常用的SQLAlchemy查詢執行器

方法 說明
all() 以列表形式返回查詢的所有結果
first() 返回查詢的第一個結果,如果未查到,返回None
first_or_404() 返回查詢的第一個結果,如果未查到,返回404
get() 返回指定主鍵對應的行,如不存在,返回None
get_or_404() 返回指定主鍵對應的行,如不存在,返回404
count() 返回查詢結果的數量
paginate() 返回一個Paginate對象,它包含指定范圍內的結果

查詢:filter_by精確查詢

返回名字等于wang的所有人

User.query.filter_by(name='wang').all()

first()返回查詢到的第一個對象

User.query.first()

all()返回查詢到的所有對象

User.query.all()

filter模糊查詢,返回名字結尾字符為g的所有數據。

User.query.filter(User.name.endswith('g')).all()

get(),參數為主鍵,如果主鍵不存在沒有返回內容

User.query.get()

邏輯非,返回名字不等于wang的所有數據。

User.query.filter(User.name!='wang').all()

邏輯與,需要導入and,返回and()條件滿足的所有數據。

from sqlalchemy import and_ User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

邏輯或,需要導入or_

from sqlalchemy import or_ User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

not_ 相當于取反

from sqlalchemy import not_ User.query.filter(not_(User.name=='chen')).all()

查詢數據后刪除

user = User.query.first() db.session.delete(user) db.session.commit() User.query.all()

更新數據

user = User.query.first() user.name = 'dong' db.session.commit() User.query.first()

使用update

User.query.filter_by(name='zhang').update({'name':'li'})

關聯查詢示例:角色和用戶的關系是一對多的關系,一個角色可以有多個用戶,一個用戶只能屬于一個角色。

查詢角色的所有用戶:

#查詢roles表id為1的角色 ro1 = Role.query.get(1) #查詢該角色的所有用戶 ro1.us

查詢用戶所屬角色:

#查詢users表id為3的用戶 us1 = User.query.get(3) #查詢用戶屬于什么角色 us1.role獲取單個數據get主鍵值獲取不到不會拋錯person = Person.query.get(3)db.session.delete(person)db.session.commit()firstperson = Person.query.first()獲取結果集xxx.query.allpersons = Person.query.all()xxx.query.filter_bypersons = Person.query.filter_by(p_age=15)xxx.query.filterpersons = Person.query.filter(Person.p_age < 18)persons = Person.query.filter(Person.p_age.__le__(15))persons = Person.query.filter(Person.p_name.startswith("小"))persons = Person.query.filter(Person.p_name.endswith("1"))persons = Person.query.filter(Person.p_name.contains("1"))persons = Person.query.filter(Person.p_age.in_([15, 11]))數據篩選order_bypersons = Person.query.order_by("-p_age")limitpersons = Person.query.limit(5)offsetpersons = Person.query.offset(5).order_by("-id")offset和limit不區分順序,offset先生效persons = Person.query.order_by("-id").limit(5).offset(5)persons = Person.query.order_by("-id").limit(5)persons = Person.query.order_by("-id").offset(17).limit(5)order_by 需要先調用執行persons = Person.query.order_by("-id").offset(17).limit(5)pagination分頁器需要想要的頁碼每一頁顯示多少數據原生persons = Person.query.offset((page_num - 1) * page_per).limit(page_per)參數(page,page_per,False(是否拋異常)persons = Person.query.paginate(page_num, page_per, False).items邏輯運算與and_ filter(and_(條件))huochelist = kaihuoche.query.filter(and_(kaihuoche.id == 1,kaihuoche.name == 'lc'))或or_ filter(or_(條件))huochelist = kaihuoche.query.filter(or_(kaihuoche.id == 1,kaihuoche.name =='lc'))非not_ filter(not_(條件)) 注意條件只能有一個huochelist = kaihuoche.query.filter(not_(kaihuoche.id == 1))inhuochelist = kaihuoche.query.filter(kaihuoche.id.in_([1,2,4]))

常用的SQLAlchemy字段類型

類型名 python中類型 說明
Integer int 普通整數,一般是32位
SmallInteger int 取值范圍小的整數,一般是16位
BigInteger int或long 不限制精度的整數
Float float 浮點數
Numeric decimal.Decimal 普通整數,一般是32位
String str 變長字符串
Text str 變長字符串,對較長或不限長度的字符串做了優化
Unicode unicode 變長Unicode字符串
UnicodeText unicode 變長Unicode字符串,對較長或不限長度的字符串做了優化
Boolean bool 布爾值
Date datetime.date 時間
Time datetime.datetime 日期和時間
LargeBinary str 二進制文件

常用的SQLAlchemy列選項

選項名 說明
primary_key 如果為True,代表表的主鍵
unique 如果為True,代表這列不允許出現重復的值
index 如果為True,為這列創建索引,提高查詢效率
nullable 如果為True,允許有空值,如果為False,不允許有空值
default 為這列定義默認值

常用的SQLAlchemy關系選項

選項名 說明
backref 在關系的另一模型中添加反向引用
primary join 明確指定兩個模型之間使用的聯結條件
uselist 如果為False,不使用列表,而使用標量值
order_by 指定關系中記錄的排序方式
secondary 指定多對多中記錄的排序方式
secondary join 在SQLAlchemy中無法自行決定時,指定多對多關系中的二級聯結條件

自定義模型類

定義模型

模型表示程序使用的數據實體,在Flask-SQLAlchemy中,模型一般是Python類,繼承自db.Model,db是SQLAlchemy類的實例,代表程序使用的數據庫。

類中的屬性對應數據庫表中的列。id為主鍵,是由Flask-SQLAlchemy管理。db.Column類構造函數的第一個參數是數據庫列和模型屬性類型。

如下示例:定義了兩個模型類,作者和書名。

#定義模型類-作者 class Author(db.Model):__tablename__ = 'author'id = db.Column(db.Integer,primary_key=True)name = db.Column(db.String(32),unique=True)email = db.Column(db.String(64))au_book = db.relationship('Book',backref='author')def __str__(self):return 'Author:%s' %self.name#定義模型類-書名 class Book(db.Model):__tablename__ = 'books'id = db.Column(db.Integer,primary_key=True)info = db.Column(db.String(32),unique=True)leader = db.Column(db.String(32))au_book = db.Column(db.Integer,db.ForeignKey('author.id'))def __str__(self):return 'Book:%s,%s'%(self.info,self.lead)

創建表 db.create_all()

查看author表結構 desc author

查看books表結構 desc books

flask-migrate

數據庫遷移

在開發過程中,需要修改數據庫模型,而且還要在修改之后更新數據庫。最直接的方式就是刪除舊表,但這樣會丟失數據。

更好的解決辦法是使用數據庫遷移框架,它可以追蹤數據庫模式的變化,然后把變動應用到數據庫中。

在Flask中可以使用Flask-Migrate擴展,來實現數據遷移。并且集成到Flask-Script中,所有操作通過命令就能完成。

為了導出數據庫遷移命令,Flask-Migrate提供了一個MigrateCommand類,可以附加到flask-script的manager對象上。

首先要在虛擬環境中安裝Flask-Migrate。

pip install flask-migrate

文件:database.py

#coding=utf-8 from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate,MigrateCommand from flask_script import Shell,Managerapp = Flask(__name__) manager = Manager(app)app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db = SQLAlchemy(app)#第一個參數是Flask的實例,第二個參數是Sqlalchemy數據庫實例 migrate = Migrate(app,db) #manager是Flask-Script的實例,這條語句在flask-Script中添加一個db命令 manager.add_command('db',MigrateCommand)#定義模型Role class Role(db.Model):# 定義表名__tablename__ = 'roles'# 定義列對象id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(64), unique=True)def __repr__(self):return 'Role:'.format(self.name)#定義用戶 class User(db.Model):__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(64), unique=True, index=True)def __repr__(self):return 'User:'.format(self.username) if __name__ == '__main__':manager.run()

創建遷移倉庫

#這個命令會創建migrations文件夾,所有遷移文件都放在里面。 python database.py db init

創建遷移腳本

自動創建遷移腳本有兩個函數,upgrade()函數把遷移中的改動應用到數據庫中。downgrade()函數則將改動刪除。自動創建的遷移腳本會根據模型定義和數據庫當前狀態的差異,生成upgrade()和downgrade()函數的內容。對比不一定完全正確,有可能會遺漏一些細節,需要進行檢查.

#創建自動遷移腳本 python database.py db migrate -m 'initial migration'

更新數據庫

python database.py db upgrade

回退數據庫

回退數據庫時,需要指定回退版本號,由于版本號是隨機字符串,為避免出錯,建議先使用python database.py db history命令查看歷史版本的具體版本號,然后復制具體版本號執行回退。

python database.py db downgrade 版本號

遷移的具體步驟:

使用安裝pip install flask-migrate初始化創建migrate對象需要使用app 和 db初始化 在ext文件中migrate = Migrate()migrate.init_app(app=app, db=db)懶加載初始化結合flask-script使用在manager文件上添加command (MigrateCommand)manager.add_command("db", MigrateCommand)python manager.py db xxxinit 第一次使用migrate 生成遷移文件不能生成模型定義完成從未調用,創建對象數據庫已經有模型記錄upgrade 升級downgrade 降級創建用戶文件python manager.py db migrate --message ‘創建用戶’

李晶:

__init__.py from flask import Flask from App import settings from App.ext import init_extdef create_app(envname):app = Flask(__name__) app.config.from_object(settings.ENV_NAME.get(envname))init_ext(app)return appext.py ''' flask-script flask-blueprint flask-session flask-sqlalchemy ''' from flask_migrate import Migrate from flask_session import Session from App.models import dbdef init_ext(app):# sessionapp.config['SECRET_KEY']='10010'app.config['SESSION_TYPE']='redis'Session(app=app)# sqlalchemydb.init_app(app=app)# migratemigrate = Migrate()# 注意參數的個數migrate.init_app(app=app,db=db)models.pyfrom flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()# orm 對象關系映射 # 通過python代碼能創建表 刪除表 # flask-migrate 數據庫遷移 --》通過一些命令行參數 去直接的操作模型 不再書寫視圖函數class Animal(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)name = db.Column(db.String(32))class Goods(db.Model):id = db.Column(db.Integer, primary_key=True, autoincrement=True)name = db.Column(db.String(32))class Person(db.Model):id = db.Column(db.Integer, primary_key=True, autoincrement=True)name = db.Column(db.String(32))p_age = db.Column(db.Integer,default=18)setting.pydef get_database_uri(DATABASE):dialect = DATABASE.get('dialect') or 'mysql'driver = DATABASE.get('driver') or 'pymysql'username = DATABASE.get('username') or 'root'password = DATABASE.get('password') or '1234'host = DATABASE.get('host') or 'localhost'port = DATABASE.get('port') or '3306'database = DATABASE.get('database') or 'flaskday03'return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,driver,username,password,host,port,database)class Config():Test = FalseDebug = FalseSQLALCHEMY_TRACK_MODIFICATIONS = Falseclass DevelopConfig(Config):Debug = TrueDATABASE = {'dialect':'mysql','driver':'pymysql','username':'root','password':'1234','host':'127.0.0.1','port':'3306','database':'flaskday03'}# SQLALCHEMY_DATABASE_URI是數據庫鏈接的路徑SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class TestConfig(Config):Test = TrueDATABASE = {'dialect': 'mysql','driver': 'pymysql','username': 'root','password': '1234','host': '127.0.0.1','port': '3306','database': 'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class ShowConfig(Config):Debug = TrueDATABASE = {'dialect':'mysql','driver':'pymysql','username':'root','password':'1234','host':'127.0.0.1','port':'3306','database':'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)class ProductConfig(Config):Debug = TrueDATABASE = {'dialect':'mysql','driver':'pymysql','username':'root','password':'1234','host':'127.0.0.1','port':'3306','database':'flaskday03'}SQLALCHEMY_DATABASE_URI = get_database_uri(DATABASE)ENV_NAME = {'develop':DevelopConfig,'test':TestConfig,'show':ShowConfig,'product':ProductConfig,'default':DevelopConfig, }views.py from _operator import not_from flask import Blueprint, request, render_templatefrom App.models import Goods, Person, dbblue = Blueprint('blue',__name__)@blue.route('/') def hello_world():goods = Goods()person = Person()return 'Hello World!'@blue.route('/saveperson/') def saveperson():p = Person()p.name = '蔡徐坤'p.age = 18db.session.add(p)# flask的增刪改 一定要commitdb.session.commit()return 'ok'@blue.route('/savelist/') def savelist():p = Person()p.name = '趙麗穎'p1 = Person()p1.name = '大牛'p_list = []p_list.append(p)p_list.append(p1)db.session.add_all(p_list)db.session.commit()return 'ok'@blue.route('/deleteperson/') def deleteperson():p = Person.query.get(1)db.session.delete(p)db.session.commit()return 'ok'@blue.route('/updateperson/') def updateperson():p = Person.query.get(2)p.name = '大妞'db.session.add(p)db.session.commit()return 'ok'# 查詢單個數據 @blue.route('/getone/') def getone(): # 查詢 模型.query.xxx # 返回的是模型類型 # p = Person.query.get(3) # print(p.name) # print(type(p))p = Person.query.first()print(p.name)print(type(p))return 'getone'# 獲取結果集 @blue.route('/getresult/') def getresult():# 獲取的全部數據# ps = Person.query.all()# for p in ps:# print(p.name)# print(ps)# # list# print(type(ps))# return 'ok' # 條件查詢 filter filter_by # filter 和 filter_by的使用 # filter在參數中需要使用模型.屬性 == 值 # filter_by在參數中需要使用 屬性 = 值 # flask中條件過濾的方法返回值類型是 basequery對象 # django中條件過濾的方法的返回值類型是 queryset # p1 = Person.query.filter(Person.age == 18) # print(p1) # print(type(p1)) # p = Person.query.filter_by(age = 18) # print(p) # print(type(p)) # # lt ==> little than # lte ==> litte than equals # gt ==> great than # gte ==> great than equals # p = Person.query.filter(Person.age.__lt__(20)) # p = Person.query.filter(Person.age.__le__(20)) # p = Person.query.filter(Person.age.__gt__(20)) # p = Person.query.filter(Person.age.__ge__(20)) # p = Person.query.filter(Person.name.startswith('張')) # p = Person.query.filter(Person.name.endswith('三')) # p = Person.query.filter(Person.name.contains('王'))p = Person.query.filter(Person.name.in_(['李四','王五']))for p1 in p:print(p1.name,p1.age)print(p)print(type(p))return 'ok'# 數據篩選 @blue.route('/getselect/') def getselect():# p = Person.query.order_by('age')# 降序問題。。。。。。。# p = Person.query.order_by('-p_age')# 取前幾個數據# p = Person.query.limit(5)# 除了前幾個的數據# p = Person.query.offset(5)# 當offset和limit同時使用的時候 永遠都是offset在前 limit在后# 空的 跳過前三個 取3個# p = Person.query.limit(3).offset(3)# 跳過前三個 取3個# p = Person.query.offset(3).limit(3)# 語法錯誤# p = Person.query.offset(3).limit(3).order_by('p_age')# 當order_by 和 offset limit連用的時候 那么 order_by 必須放在前面# p = Person.query.order_by('p_age').offset(3).limit(3)# 降序# p = Person.query.order_by(db.desc(Person.p_age))p = Person.query.order_by(-Person.p_age)for p1 in p:print(p1.id,p1.name,p1.p_age)return 'ok'# 分頁 # page 第幾頁 per_page/pagesize 頁的大小@blue.route('/getpage/') def getpage():# 在瀏覽器的地址欄上輸入 127.0.0.1:5000/getpage?page=1&per_page=3page = int(request.args.get('page'))per_page = int(request.args.get('per_page'))# 1 0 3# 2 3 3# 3 6 3# offset(0).limit(3) 123# offset(3).limit(3) 456# offset(6).limit(3) 789# persons = Person.query.offset((page-1)*per_page).limit(per_page)# paginate方法的返回值類型是 pagination對象 該對象不可以直接用于迭代 如果# 想遍歷該對象 那么需要調用items# persons = Person.query.paginate(page,per_page,False).itemspersons = Person.query.paginate(page=page,per_page=per_page,error_out=False)return render_template('personlist.html',persons=persons,page=page,per_page=per_page)# 邏輯運算 @blue.route('/getlogic/') def getlogic():# persons = Person.query.filter(or_(Person.p_age==18,Person.p_age==19))# persons = Person.query.filter(and_(Person.p_age==18,Person.name=='大牛'))persons = Person.query.filter(not_(Person.id == 5))print(persons)print(type(persons))for person in persons:print(person.name,person.p_age)return 'ok'manager.py from flask_migrate import MigrateCommand from flask_script import Managerfrom App import create_app from App.views import blueapp = create_app('develop')manager = Manager(app=app)manager.add_command('db',MigrateCommand)app.register_blueprint(blueprint=blue)if __name__ == '__main__':manager.run()數據庫遷移flask-migrate使用步驟:1 pip install flask-migrate2 migrate = Migrate()3 migrate.init_app(app=app,db=db)4 manager.add_command('db',MigrateCommand)5 開始遷移python manager.py db initpython manager.py db migratepython manager.py db upgradepython manager.py db downgrade當不能生成遷移文件的時候:1 引用模型2 刪除遷移的表和遷移文件personlist.py<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><ul>{% for person in persons %}<li>{{ person.name }}</li>{% endfor %}</ul><a href="{{ url_for('blue.getpage') }}?page={{ page - 1 }}&per_page={{ per_page }}">上一頁</a><a href="{{ url_for('blue.getpage') }}?page={{ page + 1 }}&per_page={{ per_page }}">下一頁</a> </body> </html>

模型關系

一對多 class Parent(db.Model):id=db.Column(db.Integer,primary_key=True,autoincrement=True)name=db.Column(db.String(30),unique=True)children=db.relationship("Child",backref="parent",lazy=True)def __init__(self):name=self.nameclass Child(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(30), unique=True)parent_id = db.Column(db.Integer, db.ForeignKey('parent.id'))def __init__(self):name = self.namerelationship函數sqlalchemy對關系之間提供的一種便利的調用方式,關聯不同的表;backref參數對關系提供反向引用的聲明,在Address類上聲明新屬性的簡單方法,之后可以在my_address.person來獲取這個地址的person; lazy參數'select'(默認值)SQLAlchemy 會在使用一個標準 select 語句時一次性加載數據;'joined'讓 SQLAlchemy 當父級使用 JOIN 語句是,在相同的查詢中加載關系;'subquery'類似 'joined' ,但是 SQLAlchemy 會使用子查詢;'dynamic':SQLAlchemy 會返回一個查詢對象,在加載這些條目時才進行加載數據,大批量數據查詢處理時推薦使用。 ForeignKey參數代表一種關聯字段,將兩張表進行關聯的方式,表示一個person的外鍵,設定上必須要能在父表中找到對應的id值添加eg:@blue.route('/add/')def add():p = Parent()p.name = '張三'c = Child()c.name = '張四'c1 = Child()c1.name = '王五'p.children = [c,c1]db.session.add(p)db.session.commit()return 'add success' 查eg:主查從 --》 Parent--》Child@blue.route('/getChild/')def getChild():clist = Child.query.filter(Parent.id == 1)for c in clist:print(c.name)return 'welcome to red remonce'從查主@blue.route('/getParent/')def getParent():p = Parent.query.filter(Child.id == 2)print(type(p))print(p[0].name)return '開洗'一對一一對一需要設置relationship中的uselist=Flase,其他數據庫操作一樣。多對多 class User(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)name = db.Column(db.String(32))age = db.Column(db.Integer,default=18)class Movie(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)name = db.Column(db.String(32))class Collection(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)u_id = db.Column(db.Integer,db.ForeignKey(User.id))m_id = db.Column(db.Integer,db.ForeignKey(Movie.id))購物車添加@blue.route('/getcollection/')def getcollection():u_id = int(request.args.get('u_id'))m_id = int(request.args.get('m_id'))c = Collection.query.filter(Collection.u_id == u_id).filter_by(m_id = m_id)if c.count() > 0:print(c.first().u_id,c.first().m_id)# print(c)# print(type(c))# print('i am if')return '已經添加到了購物車中'else:c1 = Collection()c1.u_id = u_idc1.m_id = m_iddb.session.add(c1)db.session.commit()return 'ok'

總結

以上是生活随笔為你收集整理的Flask视图、模板、模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。