打開pycharm編譯器,新建一個Flask項目,選擇提早建好的虛擬環境 。css
項目結構:html
static:靜態資源文件,能夠直接被瀏覽器訪問前端
templates:模版文件,必須在項目的python代碼中進行渲染給前端,瀏覽器纔可訪問python
app.py:python的程序文件mysql
返回信息:能夠是字符串、html標籤、模版golang
請求流程:sql
Flask對象註冊的路由數據庫
路由映射給相應函數django
函數進行和數據交互編程
數據進行展現給前端
1 from flask import Flask 2 3 app = Flask(__name__) 4 5 @app.route('/') 6 def hello_world(): 7 return 'Hello World!' 8 9 if __name__ == '__main__': 10 app.run() # 默認只能本機訪問。app.run(host='0.0.0.0',debug=True)
11 12 """ 運行:在Terminal終端中進入到項目的文件夾下,鍵入python app.py運行 """
狀態碼http
2xx:請求成功
3xx:重定向
4xx:客戶端錯誤
5xx:服務器錯誤
路由route
1 from flask import Flask, render_template 2 app = Flask(__name__) 3 4 @app.route("/orders/",methods=["GET", "POST"]) # 能夠請求的方式爲:GET、POST。默認只支持get請求方法,想要支持其餘方法須要設置 methods=['請求方法'] 參數 5 def orders(): 6 return "Orders" 7 8 @app.route("/users/") 9 def users(): 10 return "<h1>Users</h1>" # 返回的能夠是html標籤 11 12 @app.route('/index/') 13 def hello_world(): 14 15 result = render_template("index.html") # 對模版進行渲染,爲返回給前端做準備 16 print(result) # 獲取打印的是html標籤字符串 17 return result # 返回給前端頁面展現 18 19 @app.route("/goods/<any(a,b):id>/") # 路由能夠是/goods/a;也能夠是/goods/b 20 def goods(id): # 能夠將路徑中的信息以參數的形式傳給試圖函數 21 22 print(id) 23 print(type(id)) 24 return "Goods Info" 25 26 if __name__ == '__main__': 27 app.run(host="0.0.0.0", debug=True, port=5000)
在run( )中,啓動前還能夠添加參數
在@app.route('/path/<param>/')中,參數默認param 是字符串類型,也能夠設置以下類型:
在@app.route('/path/<param>/',methods=["GET", "POST"])中,methods參數默認是get。想要支持其餘方法須要設置 methods=['請求方法'] 參數
視圖views
request全局對象: 客戶端發送給服務器的數據請求後。Flask根據客戶端的請求報文自動生成request對象,request對象不可修改
客戶端發送的請求- 裏面包含了客戶端的各類信息- Request不是客戶端建立的- 是框架根據客戶端的數據(請求報文)建立的- 屬於Flask中的內置對象
request屬性:
request.url: 完整請求地址
request.base_url: 去掉GET參數的url
request.host_url: 只有主機和端口號的url
request.path: 路由中的路徑
request.method: 請求方式
request.remote_addr: 請求的客戶端地址
request.args: GET請求參數
request.form: POST請求參數
request.files: 文件上傳
request.headers: 請求頭
request.cookie: 請求中的cookie
ImmutableMultiDict是類字典的數據結構,與字典的區別是:能夠存在相同的鍵。args和form都是ImmutableMultiDict的對象
ImmutableMultiDict中數據獲取的方式:dict['uname'] 或 dict.get('uname')。獲取指定key對應的全部值:dict.getlist('uname')
服務器返回給客戶端的數據。response是伴隨request出現的,不能主動出現。由開發者建立
返回類型:返回字符串、返回模板、返回標籤、返回Response、返回重定向、終止 abort(404)
Response返回方式:
1. 直接返回Response對象;return Response("login success")
2. 經過 make_response(date,code) 返回。date:返回的數據內容;code:狀態嗎
3. 返回文本內容,狀態碼。return "登錄成功" 或者:return 404
4. 返回模版。return render_template('req.html')
Response響應類型:
1. 直接的響應請求
2. 重定向請求:return redirect("/") 或者動態獲取:return redirect(url_for('藍圖名.視圖函數名'))
3. 終止請求: abort(400)
4. 捕獲異常: @路由名.errorhandler(狀態碼)
1 @bp.route('/resp/') 2 def resp(): 3 4 # 經過 render_template 返回字符串。響應類型是 str,頁面最終會以字符串的形式返回到前端頁面 5 # response = render_template('req.html') 6 7 # 經過 make_response 建立一個相應。響應類型是 Flask.wrappers.Response 對象 8 response = make_response("make_response") 9 10 print(type(response)) 11 return response 12 13 14 @bp.route('/redi/') 15 def redi(): 16 17 # redirect 的第一個參數 是須要跳轉的地址 18 # 相應類型:<class 'werkzeug.wrappers.Response'> 19 # 設置格式:藍圖名.視圖函數 20 21 response = redirect(url_for('blue.req')) 22 print(type(response)) 23 return response
1 from flask import Flask, render_template, request, Response, make_response, redirect, url_for, abort 2 app = Flask(__name__) 3 4 @app.route('/', methods=["GET", "POST", "PUT", "DELETE"]) # 容許請求的方式 設置methods參數。默認是get 5 def hello_world(): # 首頁視圖函數 6 print(request) # 獲取ruquest請求對象。request屬於flask中的內置對象,全局可調用 7 print(request.method) # 獲取request請求對象的請求方式 8 if request.method == "GET": 9 print(request.remote_addr) # 獲取其請求對象遠端的IP 10 print(request.args) # args是獲取get的請求參數。打印ImmutableMultiDict([])對象 11 print(request.args.get("username")) # 獲取get請求中url中的用戶名參數 12 print(request.args.get("hobby")) # 獲取get請求中url中攜帶的愛好參數 13 print(request.args.getlist("hobby")) # 獲取get請求中url中攜帶的愛好參數列表 14 return render_template('index.html') # 渲染給html頁面 15 elif request.method == "POST": 16 return "據說你是POST" 17 elif request.method == "PUT": 18 return "PUT沒聽過" 19 20 21 @app.route("/register/") # 實現註冊功能的視圖函數 22 def register(): 23 return render_template('register.html') # 頁面渲染,返回給前端html頁面 24 @app.route("/doregister/", methods=["GET", "POST"]) 25 def do_register(): 26 print(request.form) # form是獲取post請求的參數 27 username = request.form.get("username") # 獲取post請求的username參數 28 password = request.form.get("password") # 獲取post請求的password參數 29 print(username, password) # 打印獲取的參數 30 return "註冊成功" # 僞裝 數據存儲成功 31 32 33 @app.route("/login/") # 實現登錄功能的視圖函數 34 def login(): 35 return render_template('login.html') # 頁面渲染,返回給前端html頁面 36 @app.route("/dologin/", methods=["POST"]) 37 def do_login(): 38 print(request.form) # form是獲取post請求的參數 39 username = request.form.get("username") # 獲取post請求的username參數 40 password = request.form.get("password") # 獲取post請求的password參數 41 print(username, password) # 打印獲取的參數 42 # return '登錄成功' # 僞裝 數據讀取、數據校驗 43 # response = Response("login success") # 返回response信息 44 response = make_response("login fail", 400) # 返回response信息。返回登錄失敗 45 return response 46 47 48 @app.route("/users/") 49 def users(): 50 return redirect("/") # 重定向到根目錄 51 # return redirect(url_for('do_register')) # 重定向到do_register視圖函數上。也能夠在html文件中使用實現頁面跳轉 52 # abort(400) # 返回響應數字。終止請求 53 54 if __name__ == '__main__': 55 app.run(debug=True, host="0.0.0.0")
1 # 終止請求,自動設置模擬異常 2 @bp.route('/error/404') 3 def error_404(): 4 # 模擬服務器資源不存在的狀況,若是資源不存在,則告訴瀏覽器 404錯誤 5 abort(404) 6 7 @bp.route('/error/500') 8 def error_500(): 9 # 模擬服務器代碼報錯的狀況,abort以後的代碼不會再被執行 10 abort(500) 11 12 13 # 捕獲異常,未拋出的異常不會被捕獲到 14 @bp.errorhandler(404) 15 def error_hander(exception): # exception獲取錯誤參數 16 print(exception) 17 return '服務器走丟了' 18 19 @bp.errorhandler(500) 20 def server_error(exception): 21 print(exception) 22 return "服務器開小差了"
1 <!-- Font Awesome Icons --> 2 <link rel="stylesheet" href="{{ url_for("static",filename="css/fontawesome-free/css/all.min.css") }}"> 3 <!-- Theme style --> 4 <link rel="stylesheet" href="{{ url_for("static",filename="css/adminlte.min.css") }}"> 5 6 {# static是靜態文件名字,動態獲取靜態文件的路徑,而後和後面的相對路徑拼接上獲取真實路徑 #} 7 8 9 10 <ul> 11 {% for student in student_list %} 12 <li><a href="{{ url_for("student",id=student.id) }}">{{ student.name }}</a></li> 13 {% endfor %} 14 </ul> 15 16 {# 實現頁面跳轉,id是student視圖函數的參數 #}
url_for 函數⽤於構建指定函數的 URL。它把 路由.函數名. 做爲第一個參數。
能夠接受任意個關鍵字參數,每一個關鍵字參數對應 URL 中的變量。未知變量將添加到 URL 中做爲查詢參數。
1 @bp.route('/args/<string:name>/<int:age>/') 2 def args(name, age): 3 print(request.args) 4 return 'name: {}, age: {}'.format(name, age) 5 6 @bp.route('/redi/') 7 def redi(): 8 # /args/Tom/19/?a=1&b=2 9 return redirect(url_for('blue.args', name='Tom', age=19, a=1, b=2))
1 import random 2 from flask import Blueprint, render_template 3 from sqlalchemy import distinct, not_, and_, or_ 4 from app.models import User, db, Grade, Student, Profile 5 6 bp = Blueprint("blue",__name__) 7 8 # 向模版中傳遞參數去渲染。列表類型。 9 @bp.route("/articles/") 10 def article_list(): 11 # 從數據庫中獲取數據,類型是:list。list中的每個數據是一個對象;一個對象對應數據庫中的一行數據 12 # articles = Article.query.with_entities('id', 'title', 'content').all() 13 14 list_str = ["Tom", "Suan", "Linli", "Bob", "Sufei"] 15 return render_template("article.html", list_str=list_str) 16 17 # 從路由中獲取參數。字符串類型。 18 @bp.route("/articles/<string:article_id>/") 19 def article_detail(article_id): 20 return article_id
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <ul> 9 {% for foo in list_str %} {# 頁面跳轉URL:http://127.0.0.1:5000/articles/4/?dee=4&abc=566。article_id=foo 實現對參數的傳遞 #} 10 <li><a href="{{ url_for('blue.article_detail', article_id=foo, dee=4, abc=566) }}">{{ foo }}</a> 11 </li> 12 {% endfor %} 13 </ul> 14 </body> 15 </html>
模版在程序中主要是呈現給用戶的界面展現的,在MTV中充當T的角色,實現了VT解耦合。
開發中VT的對應關係是:N:M的關係。一個V能夠調用任意T,一個T能夠被任意V調用。
Flask中使用Jinja2模版引擎。Jinja2由Flask的做者開發,是一個現代化設計和友好的python模版語言。模仿的是django的模版語言
優勢:
1. 速度快,被普遍使用
2. html設計和後端python開發分離
3. 減小python複雜度
4. 很是靈活,快速和安全
5. 提供了控制、繼承等高級功能
模版處理分爲兩個過程:
1. 加載,在模版中使用視圖函數中傳遞過來的數據
2. 渲染,在視圖中經過關鍵字參數的形式傳遞參數
模版代碼包含兩部分:
1. 靜態html
2. 動態插入的代碼段
模版語法分類:
1. 變量:模版中的變量,{{ var }}
視圖傳遞給模版的數據、前面定義出來的數據、變量不存在的話默認忽略
2. 標籤:模版中的標籤,{% tag %}
控制邏輯、使用外部表達式、建立變量、宏定義
1 from flask import Flask, render_template 2 3 app = Flask(__name__) 4 5 @app.route('/') # 傳入參數給html,模版渲染 6 def hello_world(): 7 return render_template('FlaskTemplate.html',msg='而後你沒有帶傘') 8 9 if __name__ == '__main__': 10 app.run(debug=True)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Index</title> 6 </head> 7 <body> 8 9 <h1>據說今天有雷陣雨</h1> 10 <h3>{{ msg }}</h3> 11 12 </body> 13 </html>
1. 父類中結構標籤 block:
{% block xxx %} block :塊操做、坑。父模板挖坑子模板填坑。
{% endblock %} endblock:挖坑繼承體現的是化整爲零的操做
2. 子類中結構標籤 extends:
{% extends 'xxx' %} 繼承、擴展。子模板能夠填充父類中的塊坑。沒有填充的塊會自動優化掉
{% super() %} 繼承後保存父塊中的內容
1 {# base文件中挖的坑信息 #} 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>{{ title }}</title> 7 </head> 8 <body> 9 {# 頭部信息 挖的坑#} 10 {% block header %} 11 {% endblock %} 12 13 {# 輪播信息 挖的坑#} 14 {% block banner %} 15 {% endblock %} 16 17 {# 內容信息 挖的坑#} 18 {% block content %} 19 {% endblock %} 20 21 {# 尾部信息 挖的坑#} 22 {% block footer %} 23 {% endblock %} 24 </body> 25 </html>
1 {# home.html模板 繼承自 base.html模板 #} 2 {% extends 'base.html' %} 3 4 {# 對繼承的header進行數據填充 #} 5 {% block header %} 6 <h1>子類模版繼承父類模版的坑,填坑</h1> 7 {% endblock %}
1 {# home1.html模版 繼承自 home.html模版。home模版中的信息,home1都會繼承過來 #} 2 {% extends 'home.html' %} 3 4 {# 若是孫類中重新賦值新的信息給子類中的坑,子類中的信息會被覆蓋掉 #} 5 {% block header %} 6 {# 禁止覆蓋其父類中的信息 #} 7 {{ super }} 8 <h2>子類中的信息,會被孫類覆蓋掉</h2> 9 {% endblock %} 10 {# 孫類中繼續挖坑,在其子類中還能夠繼續填坑 #} 11 {% block content %} 12 {% block left %} 13 {% endblock %} 14 15 {% block right %} 16 {% endblock %} 17 {% endblock %}
block:塊,坑。塊沒有填充,會被自動優化掉,不會報錯
首次出現表明定義一個塊表明界面的一種規劃;
二次出現表明對既有塊填充;塊中能夠繼續規劃新的塊
三次出現表明對既有塊的填充,會覆蓋上一次的內容,不想被覆蓋,使用{{ super() }}。
extends:繼承,模板的繼承。block + extends:化整爲零
3. 包含 include:
{% include %} include 包含,將其餘html文件的內容包含進來,體現的是 由零到一 的概念。效率沒有上面的高
1 {# header.html #} 2 <h2>這是一個頭</h2>
1 {# content.html #} 2 <h2>這是一個內容</h2>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首頁</title> 6 </head> 7 <body> 8 {% include 'home.html' %} 9 {% include 'content.html' %} 10 </body> 11 </html>
4. 宏定義 marco:
{% marco hello(name) %}
{{ name }}
{% endmarco %} marco 宏定義,能夠在模版中定義函數,在其餘地方調用
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首頁</title> 6 </head> 7 <body> 8 {# 編寫宏 #} 9 {% macro hello(name) %} 10 <h1>你好{{ name }}這是一個宏標籤</h1> 11 {% endmacro %} 12 {# 調用宏 #} 13 {{ hello('小明') }} 14 {{ hello('小紅') }} 15 </body> 16 </html>
{% from 'xxx' import xxx %} 宏定義可導入
1 {# haha.html文件 #} 2 {% macro haha() %} 3 <h1>哈哈大笑</h1> 4 {% endmacro %} 5 6 7 8 9 <!DOCTYPE html> 10 <html lang="en"> 11 <head> 12 <meta charset="UTF-8"> 13 <title>首頁</title> 14 </head> 15 <body> 16 {# 導入宏 #} 17 {% from 'haha.html' import haha %} 18 {# 使用宏 #} 19 {{ haha() }} 20 </body> 21 </html>
1. 循環控制 {% for item in items %}......{% endfor %}
循環器loop
loop.first 選擇第一個數據
loop.last 選擇最後一個數據
loop.index 帶序號顯示數據
loop.revindex 反轉序號顯示
loop.index0 從0序號開始顯示
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首頁</title> 6 </head> 7 <body> 8 {% for habby in habbies %} 9 {# 帶序號的顯示愛好信息 #} 10 <li>{{ loop.index }}{{ habby }}</li> 11 {% endfor %} 12 </body> 13 </html>
2. 邏輯控制 {% if exp %}...{% elif exp %}...{% else exp %}...{% endif %}
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首頁</title> 6 </head> 7 <body> 8 {% for habby in habbies %} 9 {% if loop.first %} 10 <li style="color:red">{{ habby }}</li> 11 {% elif %} 12 <li style="color: green">{{ habby }}</li> 13 {% else %} 14 <li>{{ habby }}</li> 15 {% endif %} 16 {% endfor %} 17 </body> 18 </html>
過濾器名稱:capitalize;lower;upper;title;trim;reverse;format;striptags 渲染以前,將值中標籤去掉
過濾器名稱:sort;sum;length;first;last;default;safe 將返回數據中的標籤渲染出來,確保數據不是js破壞代碼再用
1 {% for habby in habbies %} 2 {% if loop.first %} 3 <li style="color:red">{{ habby }}</li> 4 {% elif %} 5 <li style="color: green">{{ habby|reverse }}</li> 6 {% else %} 7 <li>{{ habby|upper }}</li> 8 {% endif %} 9 {% endfor %}
Flask 默認沒有提供任何數據庫操做的API,可選擇任意合適本身項目的數據庫:可用原生數據庫語、也可用ORM實現功能(SQLAlchemy 或 MongoEngine)
開發效率高,設計靈活能夠輕鬆完成複雜查詢
移植性高,能夠對接多種數據庫,實現了防SQL注入
易於理解,便於維護(將數據轉換爲面向對象編程)
執行效率低,由於須要將對象的操做轉換爲數據庫的SQL。對於複雜操做可能沒有支持
代碼利用率低、條件複雜代碼語句越長、有不少類似的語句。
一些SQL是在業務邏輯中拼出來的,若修改SQL須要瞭解業務邏輯,
直接寫SQL容易忽視SQL問題(SQL注入問題)
安裝 flask-sqlalchemy:pip install flask-sqlalchemy
安裝 pymysql驅動 :pip install pymysql
常見字段
Integer 整型數字 SmallInteger 小型整數 BigInteger 大型整數 Float 浮點類型 Numeric 數字型
String 字符串 Text 文本 Unicode 編碼 Unicode Text 編碼文本 Boolean 布爾
Date 時間 Time 時間 DateTime 時間 Interval 二進制 LargeBinary 二進制
常見約束
primary_key 主鍵 autoincrement 自增 unique 惟一 index 索引,常差字段加索引
nullable 是否爲空 default 默認值 ForeignKey() 外鍵,用來約束級聯數據(db.Column( db.Integer, db.ForeignKey(xxx.id) ))
提交數據
在事務處理中,對象(數據)插入、修改、刪除是基於查詢的
db.session.add(object) 把對象(數據)添加到數據庫中
db.session.add_all(list_obj)把一組對象添加到數據庫中
db.session.commit() 將要新添加的數據進行提交
db.session.delete() 對查到的對象(數據)進行刪除
1 import random 2 from flask import Flask, render_template 3 from flask_sqlalchemy import SQLAlchemy 4 5 app = Flask(__name__) 6 # 配置鏈接mysql數據庫的指定信息。dialect+driver://username:password@host:port/database 7 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:guoyapeng@localhost:3306/FlaskModel' 8 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 設False爲更好的兼容性,禁止對象追蹤修改 9 db = SQLAlchemy(app) 10 11 12 # 建立班級表 13 class Grade(db.Model): # 主表 14 id = db.Column(db.Integer,primary_key=True,autoincrement=True) # id字段:整型、主鍵、自增 15 name = db.Column(db.String(32),unique=True,nullable=False) # name字段:字符串型、惟1、不可爲空 16 # 建立學生表 17 class Student(db.Model): # 從表 18 id = db.Column(db.Integer,primary_key=True,autoincrement=True) # 學生id: 整型,主鍵,自增 19 name = db.Column(db.String(32),nullable=False) # 學生姓名:整型,字符串,不爲空 20 grade = db.Column(db.Integer,db.ForeignKey(Grade.id)) # 學生班級:整型,外鍵:Grade表中
1 # 新建數據庫表的url 2 @app.route('/create/') 3 def create(): 4 db.create_all() # 建立數據庫 5 return '數據庫表建立成功'
1 # 添加C 班級數據信息 2 @app.route('/addgrade/') 3 def add_grade(): 4 grade = Grade() 5 grade.name = 'python%d' % random.randrange(1000) 6 7 db.session.add(grade) 8 db.session.commit() 9 return '添加成功' 10 # 添加C 學生數據信息 11 @app.route("/addstudent/") 12 def add_student(): 13 student = Student() 14 student.name = "Tom%d" % random.randrange(10000) 15 16 grade_list = Grade.query.all() 17 grade = grade_list[random.randrange(len(grade_list))] 18 student.grade = grade.id 19 20 db.session.add(student) 21 db.session.commit() 22 return "添加成功"
1 # 查詢R 班級列表信息 2 @app.route('/grades/') 3 def grades(): 4 grade_list = Grade.query.all() 5 return render_template('GradeLIst.html',grade_list=grade_list) 6 # 查詢R 學生列表信息 7 @app.route('/students/') 8 def students(): 9 student_list = Student.query.all() 10 return render_template('StudentList.html',student_list=student_list)
1 # 查詢單個班級信息,並顯示本班全部的學生。路由是:http://127.0.0.1:5000/grade/2/ 2 @app.route('/grade/<int:id>/') 3 def grade(id): 4 grades = Grade.query.filter(Grade.id.__eq__(id)).all() # 查詢id等於指定參數id的信息,加.all()以列表形式獲取全部數據 5 # grades = Grade.query.filter(Grade.id == id) 同上方法。結果是:sql語句。類型是:basequery對象 6 grade = grades[0] # 獲取列表中的第一個班級元素 7 student_list = Student.query.filter(Student.grade == id).all() 8 return render_template('Grade.html',grade=grade,student_list=student_list) 9 # 查詢單個學生的信息。路由是:http://127.0.0.1:5000/student/2/ 10 @app.route('/student/<int:id>/') 11 def student(id): 12 student = Student.query.get(id) # 獲取指定id的學生 13 return render_template('student.html',student=student) 14 15 if __name__ == '__main__': 16 app.run()
1 # 數據庫D 對數據刪除 2 @bp.route("/delete/") 3 def delete(): 4 #刪除時,必須先查詢到數據,再對對象進行刪除 5 user = User.query.get(1) 6 # 經過 delete 刪除一個數據 7 db.session.delete(user) 8 # 對象刪除完後,執行commit向數據庫提交更新 9 db.session.commit() 10 return "update ok"
Python語言中的ORM(SQLAlchemy)。下載安裝包針對於Flask的支持:pip install flask-sqlalchemy
1 from flask import Flask, render_template 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 # 配置鏈接sqlite數據庫的指定信息。 7 app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hello.sqlite' 8 # 設False爲更好的兼容性,禁止對象追蹤修改 9 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 10 # SQLite數據庫鏈接不須要額外驅動,也不須要用戶名和密碼 11 db = SQLAlchemy(app) 12 13 14 # 配置鏈接mysql數據庫的指定信息。dialect+driver://username:password@host:port/database 15 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:guoyapeng@localhost:3306/FlaskModel' 16 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 17 db = SQLAlchemy(app) 18 19 20 if __name__ == '__main__': 21 app.run()
db.create_all():建立數據庫表
db.drop_all():刪除數據庫表
1 @bp.route("/create_db/") 2 def create_db(): 3 """ 4 建立表 5 """ 6 from app.models import db 7 db.create_all() 8 return "db create" 9 @bp.route("/drop_db/") 10 def drop_db(): 11 """ 12 刪除表 13 """ 14 from app.models import db 15 db.drop_all() 16 return "db drop"
1 from flask_script import Manager 2 from app import create_app 3 4 app = create_app() 5 manager = Manager(app) 6 7 if __name__ == '__main__': 8 manager.run()
1 import os 2 from flask import Flask 3 from app import views 4 from app.models import db 5 6 def create_app(): 7 8 app = Flask(__name__) 9 10 # sqlite3 數據庫文件地址 11 db_file = os.path.join(app.root_path,"sqlite.db") 12 # 指定數據庫的 URI 13 app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + db_file 14 15 # 關閉 SQLAchemy 底層對象監聽功能 16 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 17 # 打印sql語句設置 18 app.config["SQLALCHEMY_ECHO"] = True 19 20 # 使用 flask app 初始化 SQLAchemy 21 db.init_app(app=app) 22 23 app.register_blueprint(views.bp) 24 25 return app
1 """ 2 flask 使用 ORM 的步驟 3 1。 指定數據庫鏈接。並創建SQLAlchemy對象 4 app.config["SQLALCHEMY_DATABASE_URI"] 5 2。 定義模型類 6 3。 經過 ORM 將模型類 轉換成 數據庫中的表 7 4。 經過模型類進行curd 8 """ 9 import datetime 10 from flask_sqlalchemy import SQLAlchemy 11 12 db = SQLAlchemy() # 實例化SQLAlchemy 13 14 class User(db.Model): 15 __tablename__ = "users" 16 17 id = db.Column(db.Integer,primary_key=True,autoincrement=True) 18 name = db.Column(db.String(16),nullable=False) 19 age = db.Column(db.Integer,default=18) 20 21 def __repr__(self): # 自定義打印效果 22 return "<User,id:{},name:{},age:{}>".format(self.id, self.name, self.age) 23 24 """ 25 繼承 db.Model 說明此類是一個 SQLAlchemy 的模型類 26 db.Column 定義模型類屬性對應的數據庫關係 27 28 默認的表名規則: 29 模型名的小寫,User -> user 30 若是是駝峯型,UserModel -> user_model 31 能夠經過 __tablename__ 自定義表名 32 33 db。Colume 定義模型類屬性對應的數據庫表字段關係 34 默認的字段名爲屬性名 35 須要爲每一個屬性指定數據庫中使用的類型 36 db.Integer 整型 37 db.String(size) 字符串,size爲最大長度 38 db.Text 長文本 39 db.DataTime 時間日期,python datetime對象 40 db.Boolean 布爾類型 41 42 primary_key : 是否爲主鍵 43 nullable : 是否爲空 44 unique : 惟一約束 45 index : 索引 46 autoincrement : 自增(默認爲auto) 47 """
1 """ 2 User.query 3 query 是一個查詢接口,BaseQuery的對象。不真正執行SQL 4 .all() 得到全部記錄,真正執行 SQL 查詢數據 5 .first() 獲取第一條數據,真正執行 SQL 查詢數據 6 .get(pk) 根據主鍵查詢 7 8 .filter() where 條件。支持更豐富的查詢條件 9 filter(User.age > 18) 10 filter(User.age == 18) 11 .filter_by() where 條件。只能經過關鍵字賦值 12 filter_by(name=XXX,age=XXX) 13 :return: 14 """
1 import random 2 from flask import Blueprint 3 from sqlalchemy import distinct, not_, and_, or_ 4 from app.models import User, db, Grade, Student, Profile 5 6 bp = Blueprint("blue",__name__)
1 """-----------------建立庫 刪除庫-----------------------""" 2 @bp.route("/create_db/") 3 def create_db(): 4 """ 5 建立表 6 """ 7 from app.models import db 8 db.create_all() 9 return "db create" 10 @bp.route("/drop_db/") 11 def drop_db(): 12 """ 13 刪除表 14 """ 15 from app.models import db 16 db.drop_all() 17 return "db drop"
1 """-------------------- 增 -------------------- """ 2 # 數據庫C操做。建立數據 3 @bp.route("/create/") 4 def create(): 5 user = User() 6 user.name = "老王" 7 user.age = 88 8 9 db.session.add(user) 10 db.session.commit() 11 return "create" 12 13 @bp.route("/creates/") 14 def creates(): 15 users = [] 16 for i in range(10): 17 name = "jack-{}".format(i) 18 age = random.randint(18,55) 19 u = User(name=name,age=age) 20 users.append(u) 21 # add_all 接收一組數據,實現批量新增數據 22 db.session.add_all(users) 23 db.session.commit() 24 return "creates"
1 """--------------------- 改 --------------------""" 2 # 數據庫U。對數據更新 3 @bp.route("/update/") 4 def update(): 5 #更新時,必須先查詢到數據,再對對象進行更新 6 user = User.query.get(1) 7 user.age = 17 8 9 # 對象修改完後,執行commit向數據庫提交更新 10 db.session.commit() 11 return "update ok"
1 """--------------------- 刪 ------------------""" 2 # 數據庫D。對數據刪除 3 @bp.route("/delete/") 4 def delete(): 5 #刪除時,必須先查詢到數據,再對對象進行刪除 6 user = User.query.get(1) 7 # 經過 delete 刪除一個數據 8 db.session.delete(user) 9 10 # 對象刪除完後,執行commit向數據庫提交更新 11 db.session.commit() 12 return "update ok"
1 """--------------------- 查 ---------------------""" 2 # 數據庫R。查詢數據 3 @bp.route("/read/") 4 def read(): 5 # 根據主鍵獲取 user 對象。若是主鍵不存在,則返回 None 6 user = User.query.get(2) # 查詢id爲3的人員信息 7 user = User.query.first() # 查詢第一我的員信息 8 9 # filter_by 中的關鍵字參數的參數名爲 要查詢模型的屬性名,即數據庫字段 10 # 過濾查詢,打印的是mysql語句。類型:<class 'flask_sqlalchemy.BaseQuery'>實例 11 user = User.query.filter_by(name="jack-0").first() # .first() 獲取對象中的第一個數據信心 12 user = User.query.filter_by(age=19,name="jack").all() # .all()獲取的是一組數據,類型是list。值是User模型對象列表 13 user = User.query.filter(User.age == 41).all() # 另一種寫法 14 15 # 按需查詢 年齡爲41歲人員的名字。with_entities 按需查詢字段 16 user = User.query.with_entities(User.name).filter_by(age=41).all() 17 18 # distinct 按年齡字段去重 19 user = User.query.with_entities(distinct(User.age)).all() 20 21 22 # filter 中的關鍵字參數的參數名爲 要查詢模型的屬性名,即數據庫字段 23 # 條件查詢。查詢年齡字段小於39歲的人員信息 24 user = User.query.filter(User.age <= 39).all() 25 26 # like 'jack%' 27 users = User.query.filter(User.name.startswith('jack')).all() 28 # like '%jack' 29 users = User.query.filter(User.name.endswith('jack')).all() 30 # like '%jack%' 31 users = User.query.filter(User.name.contains('jack')).all() 32 33 # 指定範圍內。age in [19, 38, 42] 34 users = User.query.filter(User.age.in_([19, 38, 42])).all() 35 36 # 排序 37 users = User.query.order_by('age') 38 users = User.query.order_by(User.age.desc()) 39 40 # not 非 41 users = User.query.filter(User.age != 19).all() 42 users = User.query.filter(not_(User.age == 19)).all() 43 # and 與 44 users = User.query.filter(and_(User.age == 19, User.name == 'jack-0')).all() 45 users = User.query.filter(User.age == 19, User.name == 'jack-0').all() 46 users = User.query.filter_by(age=19, name='jack-0') 47 # or 或 48 users = User.query.filter(or_(User.age == 19, User.age == 42)).all() 49 50 print(users) 51 return 'read'
模型關係
從表中,定義外鍵字段;主表中,定義關係。(誰聲明外鍵誰是從表)
1 # 1:n Grade:Student 2 class Grade(db.Model): 3 __tablename__ = "grades" 4 5 g_id = db.Column(db.Integer,primary_key=True) # 主鍵 6 7 created_at = db.Column(db.DateTime,default=datetime.datetime.now()) 8 9 # 經過設置onupdate 在對象更新時,自動更新updated_at。能夠幫助統計天天註冊人數 10 11 updated_at = db.Column(db.DateTime,default=datetime.datetime.now(),onupdate=datetime.datetime.now()) 12 13 g_name = db.Column(db.String(16),unique=True,nullable=False) 14 15 # 注意⚠️:db.relationship() 定義一個模型關係(Colume是關係到數據庫中)。提供了可讓Grade對象 g 經過g.students的方式訪問N(多)的一方數據的便利性。 16 # 第一參數:關係N方模型的類名;第二參數backref: 反響關係引用,反向在Student方新增grade字段(屬性),方便Student對象s.grade訪問1方字段;第三參數lazy:加載關聯關係數據的時機 17 # lazy = Ture/"select"時 會發送兩條sql語句,一條查 one 的一方;一條查 many的一方 18 # lazy = False/"joined" 時 會發送一條sql語句,經過LEFT JOIN 的方式查詢 one 一方 和 many 一方數據 19 # lazy = "dynamic" 時 會發送一條 sql語句,只查詢 one 一方的數據,many 一方的關聯屬性是一條 Query 對象, 20 # 不會真實執行查詢,在須要時,調用students.all() 真正去數據庫中查詢數據 21 students = db.relationship("Student",backref="grade",lazy=True) 22 23 24 class Student(db.Model): 25 __tablename__ = "students" 26 27 s_id = db.Column(db.Integer, primary_key=True) # 主鍵 28 29 created_at = db.Column(db.DateTime, default=datetime.datetime.now()) 30 31 # 經過設置onupdate 在對象更新時,自動更新updated_at。能夠幫助統計天天註冊人數 32 updated_at = db.Column(db.DateTime, default=datetime.datetime.now(), onupdate=datetime.datetime.now()) 33 34 s_name = db.Column(db.String(16),unique=False) 35 36 s_age = db.Column(db.Integer,default=18,nullable=False) 37 38 # db.ForeignKey() 用於定義外鍵,參數:主標的表名.主鍵名 39 grade_id = db.Column(db.Integer,db.ForeignKey("grades.g_id")) 40 41 # one to one 的聲明方式和 one to many 幾乎一致,區別在於: 42 # 不使用 lazy。使用 uselist = Flase 來模擬只返回一條數據 43 profile = db.relationship("Profile",backref= "student",uselist=False) 44 45 46 # 1:1 Student:Profile 47 class Profile(db.Model): 48 __tablename__ = "profiles" 49 50 id = db.Column(db.Integer,primary_key=True) # 主鍵 51 52 created_at = db.Column(db.DateTime, default=datetime.datetime.now()) 53 54 # 經過設置onupdate 在對象更新時,自動更新updated_at。能夠幫助統計天天註冊人數 55 updated_at = db.Column(db.DateTime, default=datetime.datetime.now(), onupdate=datetime.datetime.now()) 56 57 phone = db.Column(db.String(16),unique=True,nullable=False) 58 59 student_id = db.Column(db.Integer,db.ForeignKey("students.id"))
1 @bp.route('/o2o-create/') 2 def o2o_create(): 3 # p = Profile(phone='13888888881') 4 # db.session.add(p) 5 # db.session.commit() 6 p = Profile.query.filter_by(phone='13888888888').first() 7 8 s = Student.query.first() 9 s.profile = p # s.profile_id = p.id 10 11 db.session.commit() 12 return 'o2o_create' 13 14 15 @bp.route('/o2o-read/') 16 def o2o_read(): 17 s = Student.query.filter_by(name='tom-0').first() 18 print(s.profile.phone) 19 20 p = Profile.query.filter_by(phone='13888888888').first() 21 print(p.student.name) # 經過Profile模型的對象p 去獲取Student模型中的name屬性值 22 23 return 'o2o_read'
1 @bp.route("/o2m_create/") 2 def o2m_create(): 3 """ 4 1:n 新增操做 5 :return: 6 """ 7 python1901 = Grade(g_name='python-1901') 8 python1902 = Grade(g_name='python-1902') 9 python1903 = Grade(g_name='python-1903') 10 11 grades = [python1901,python1902,python1903] 12 db.session.add_all(grades) 13 db.session.commit() 14 15 students = [] 16 for i in range(30): 17 name = 'tom-{}'.format(i) 18 age = 18 + random.randint(0,5) 19 20 s = Student(s_name=name,s_age=age) 21 22 # ⚠️經過反向引用的屬性賦值,也能夠只經過 grade_id 進行賦值、 23 s.grade = random.choice(grades) # 隨機選取一個班級對象。將班級對象 g 賦值給 s.grade。本質上至關於:s.grade_id = g.id 24 students.append(s) 25 26 db.session.add_all(students) 27 db.session.commit() 28 return "o2m create ok" 29 30 31 @bp.route("/o2m_read/") 32 def o2m_read(): 33 # 經過班級查詢獲取班級下的全部學生 34 g = Grade.query.first() 35 # 當lazy= "dynamic" 時,g.students 是一個 Query 對象,只有經過 g.students.all() 纔會發送 SQL 語句,執行查詢 36 # print(type(g.students)) 37 # print(g.students.all()) 38 39 # 經過Student對象s獲取Grade模型中的班級名字字段 40 s = Student.query.first() 41 print(s.grade.g_name) 42 return "o2m_read ok" 43 44 @bp.route('/o2m_update/') 45 def o2m_update(): 46 tom_4 = Student.query.filter_by(s_name='tom-4').first() 47 python_1902 = Grade.query.filter_by(g_name="python-1902").first() 48 # 更改學生班級信息。至關於:tom_4.grade_id = python_1902.id 49 tom_4.grade = python_1902 50 db.session.commit() 51 return "02m_update ok" 52 53 @bp.route('/o2m_delete/') 54 def o2m_delete(): 55 # 笨辦法 56 # python_1902 = Grade.query.filter_by(name='python-1902').first() 57 # tom_4 = Student.query.filter_by(name="tom-4").first() 58 # 59 # python_1902.students.remove(tom_4) 添加時: python1902.student.append(s) 60 # db.session.commit() 61 62 python_1901 = Grade.query.filter_by(name="python-1901").first() 63 db.session.delete(python_1901) 64 db.session.commit() 65 return "o2m_delete ok"
1 # 笨辦法。僞代碼 2 Student(db.Model) 3 id, name 4 Group (db.Model) 5 id, name, 6 StudentGroup(db.Model) 7 id, student_id(fk,student.id), group_id(fk,group.id) 8 9 10 s = Student(name="Tom") 11 db.session.add(s) 12 db.session.commit() 13 14 g = Group(name="Html") 15 db.session.add(g) 16 db.session.commit() 17 18 19 sg = StudentGroup() 20 sg.student_id = s.id 21 sg.group_id = g.id 22 db.session.add(sg) 23 db.session.commit()
1 # 多對多(普通方式) 2 class User(db.Model): 3 id = db.Column(db.Integer,primary_key=True,autoincrement=True) 4 name = db.Column(db.String(32)) 5 age = db.Column(db.Integer,default=18) 6 7 class Movie(db.Model): 8 id = db.Column(db.Integer,primary_key=True,autoincrement=True) 9 name = db.Column(db.String(32)) 10 11 class Collection(db.Model): 12 id = db.Column(db.Integer,primary_key=True,autoincrement=True) 13 u_id = db.Column(db.Integer,db.ForeignKey(User.id)) 14 m_id = db.Column(db.Integer,db.ForeignKey(Movie.id)) 15 16 # 購物車添加 17 @blue.route('/getcollection/') 18 def getcollection(): 19 u_id = int(request.args.get('u_id')) 20 m_id = int(request.args.get('m_id')) 21 c = Collection.query.filter(Collection.u_id == u_id).filter_by(m_id = m_id) 22 23 if c.count() > 0: 24 print(c.first().u_id,c.first().m_id) 25 # print(c) 26 # print(type(c)) 27 # print('i am if') 28 return '已經添加到了購物車中' 29 else: 30 c1 = Collection() 31 c1.u_id = u_id 32 c1.m_id = m_id 33 db.session.add(c1) 34 db.session.commit() 35 return 'ok'
1 class Student(db.Model): 2 __tablename__ = "students" 3 4 s_id = db.Column(db.Integer, primary_key=True) # 主鍵 5 6 created_at = db.Column(db.DateTime, default=datetime.datetime.now()) 7 # 經過設置onupdate 在對象更新時,自動更新updated_at。能夠幫助統計天天註冊人數 8 updated_at = db.Column(db.DateTime, default=datetime.datetime.now(), onupdate=datetime.datetime.now()) 9 10 s_name = db.Column(db.String(16),unique=False) 11 12 s_age = db.Column(db.Integer,default=18,nullable=False) 13 14 # db.ForeignKey() 用於定義外鍵,參數:主標的表名.主鍵名 15 grade_id = db.Column(db.Integer,db.ForeignKey("grades.g_id")) 16 17 # one to one 的聲明方式和 one to many 幾乎一致,區別在於: 18 # 不使用 lazy。使用 uselist = Flase 來模擬只返回一條數據 19 profile = db.relationship("Profile",backref= "student",uselist=False) 20 21 # many to many 的關係定義,本質是雙向的一對多關係 22 # secondary 指定多對多關係中的關係表 23 groups = db.relationship('Group', secondary='student_groups', 24 backref=db.backref('students', lazy='dynamic'), lazy='dynamic') 25 26 """ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++""" 27 28 # n:m Group:Student 29 class Group(db.Model): 30 __tablename__ = 'groups' 31 32 id = db.Column(db.Integer, primary_key=True) # 主鍵 33 34 created_at = db.Column(db.DateTime, default=datetime.datetime.now()) 35 updated_at = db.Column(db.DateTime, default=datetime.datetime.now(), onupdate=datetime.datetime.now()) 36 37 name = db.Column(db.String(32), unique=True, nullable=False) 38 39 # db.Table() 第一個參數:表名;其餘參數:字段定義 40 student_groups = db.Table('student_groups', 41 db.Column('id', db.Integer, primary_key=True), 42 db.Column('student_id', db.Integer, db.ForeignKey('students.id')), 43 db.Column('group_id', db.Integer, db.ForeignKey('groups.id')) 44 )
1 @bp.route('/m2m-init/') 2 def m2m_init(): 3 g1 = Group(name='python') 4 g2 = Group(name='html') 5 g3 = Group(name='golang') 6 7 db.session.add_all([g1, g2, g3]) 8 db.session.commit() 9 10 return 'm2m_init ok' 11 12 13 @bp.route('/m2m-create/') 14 def m2m_create(): 15 # 獲取 組模型的對象 16 python = Group.query.filter_by(name='python').first() 17 html = Group.query.filter_by(name='html').first() 18 19 # 根據學生主鍵 獲取學生對象 20 tom_0 = Student.query.get(1) 21 tom_1 = Student.query.get(2) 22 23 # 根據 組對象中的students字段添加學生tom_0 24 python.students.append(tom_0) 25 26 # 根據 學生對象的groups字段添加組html 27 tom_1.groups.append(html) 28 29 db.session.commit() 30 return 'm2m_create ok' 31 32 33 @bp.route('/m2m-delete/') 34 def m2m_delete(): 35 python = Group.query.filter_by(name='python').first() 36 html = Group.query.filter_by(name='html').first() 37 38 tom_0 = Student.query.get(1) 39 tom_1 = Student.query.get(2) 40 41 # 刪除一個不屬於 student 對象的 group 會報錯 42 # tom_0.groups.remove(python) 43 44 # 清空 html 組內的全部學生 45 html.students = [] 46 47 db.session.commit() 48 return 'm2m_delete ok'
1 import datetime 2 from flask_sqlalchemy import SQLAlchemy 3 # 實例化SQLAlchemy 4 db = SQLAlchemy() 5 6 class ModelMixin(): 7 """ 8 Mixin 是一種多繼承的模式。主要爲子類增長擴展功能 9 """ 10 11 @classmethod 12 def save_all(cls,objs): 13 """ 14 定義一個類方法(不須要實例化類就能夠被類自己調用)cls 表明當前類 15 對一組數據進行提交,成功返回True;失敗返回Flask,並數據回滾 16 僞代碼: 17 users = [user, user, user] 18 try: 19 db.session.add_all(users) 20 db.session.commit() 21 except Exception as e: 22 db.session.rollback() 23 User.save_all(users) 24 :param objs: 25 :return: 26 """ 27 try: 28 db.session.add_all(objs) # 一次性對一組數據進行存儲提交 29 db.session.commit() 30 except Exception as e: 31 db.session.rollback() # 沒有存儲成功,進行回滾操做 32 return False 33 34 35 def save(self): 36 """ 37 定義一個類(必須實例化類以後才能被調用)。self 表明當前類的實例 38 對一組數據進行提交,正確返回True;錯誤返回Flask,並數據回滾 39 僞代碼: 40 user = User(name='jack', age=55) 41 try: 42 db.session.add(user) 43 db.session.commit() 44 except Exception as e: 45 db.session.rollback() 46 user.save() 47 :return: 48 """ 49 try: 50 db.session.add(self) 51 db.session.commit() 52 return True 53 except Exception as e: 54 db.session.rollback() 55 return False 56 57 def delete(self): 58 59 try: 60 db.session.delete(self) # 刪除操做 61 db.session.commit() 62 return True 63 except Exception as e: 64 db.session.rollback() 65 return False 66 67 68 class User(ModelMixin,db.Model): 69 __tablename__ = "users" 70 71 id = db.Column(db.Integer,primary_key=True,autoincrement=True) 72 name = db.Column(db.String(16),nullable=False) 73 age = db.Column(db.Integer,default=18) 74 75 def __repr__(self): # 自定義打印效果 76 return "<User,id:{},name:{},age:{}>".format(self.id, self.name, self.age)
1 import random 2 from flask import Blueprint, render_template 3 from sqlalchemy import distinct, not_, and_, or_ 4 from app.models import db, Grade, Student, Profile 5 from app.models import User 6 7 bp = Blueprint('blue', __name__) 8 9 # 增添 10 @bp.route('/create/') 11 def create(): 12 users = [] 13 for i in range(10): 14 name = 'tom-{}'.format(i) 15 age = random.randint(18, 88) 16 u = User(name=name, age=age) 17 users.append(u) 18 19 User.save_all(users) 20 return 'create ok!' 21 22 # 刪除 23 @bp.route('/delete/') 24 def delete(): 25 # 刪除時,必須先查詢到數據,在對對象進行刪除 26 user = User.query.get(13) 27 user.delete() 28 29 return 'delete'