1.理解ORM
- ORM是MTV模型裡面的Model模型
- ORM(Object Relational Mapping),物件關係對映
- 舉例:學生選課
學生和課程這兩個實體,一個學生可以選擇多門課程,一個課程可以被多名學生選擇。這兩個實體是多對多的關係,學生選課對應的資料庫表
為什麼要學習ORM
ORM的重要特性
- 物件導向的程式設計思想,方便擴充
- 少寫(幾乎不寫)SQL,提升開發效率
- 支援多種型別的資料庫,方便切換
- ORM技術成熟,能解決絕大部分問題
2.環境安裝
2.1.Flask-sqlalchemy介紹及安裝
- PIP安裝: pip install -U Flask-SQLAlchemy
- 原始碼安裝: python setup.py install
- 使用國內映象安裝: pip install -U -i https://mirrors.aliyun.com/pypi/simple flask-sqlalchemy
常見安裝報錯:ERROR: Could not install packages due to an OSError:
解決方案:在pip install 後面加上 --user即可
備註:如果是第一次安裝flask-sqlalchemy,還需要安裝它資料庫的依賴mysqlclient。 pip install mysqlclient
安裝mysqlclient常見報錯: error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": https://visualstudio.microsoft.com/downloads/
解決方案1:https://blog.csdn.net/alicee_2012/article/details/122726986
解決方案2:https://blog.csdn.net/weixin_42403632/article/details/117087559(我的報錯是透過這個解決的)
安裝成功?
2.2.Flask-sqlalchemy配置
3.ORM的CURD操作
3.1.設計資料庫模型並建立表
資料庫模型設計
- 1)繫結到Flask物件: db=SQLAlchemy(app)
- 2)ORM模型建立:
class User(db.Model): id=db.Column(db.Integer,primary_key=True)
- 3)指定表的名稱: __tablename__='weibo_user'
建立和刪除表
- 1)手動建立資料庫
- 2)建立表: >>> db.create_all(bind='db1') #bind='db1'可以不傳,當存在需要對多個資料庫建立表時,需要新增對應的資料庫物件。只有一個庫時,不用加
- 3)刪除表: >>> db.drop_all()
例項驗證:設計資料庫模型,建立/刪除表
建立指定名稱的表
3.2.資料庫模型設計
資料庫的表肯定不止一張,同時資料表之間都會有一些關聯關係,該如何實現?
- 透過db.ForeignKey()進行外來鍵關聯
- 透過db.relationship()進行反向引用
1 from flask import Flask, render_template 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 # 配置資料庫的連線引數 6 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:*****@*******/test_flask' 7 8 db = SQLAlchemy(app) 9 10 11 class User(db.Model): #User為模型名稱,即類名為模型名稱 12 """ 使用者的基礎資訊 """ 13 __tablename__ = 'weibo_user' 14 id = db.Column(db.Integer, primary_key=True) 15 username = db.Column(db.String(64), nullable=False) 16 password = db.Column(db.String(256), nullable=False) 17 birth_date = db.Column(db.Date, nullable=True) 18 age = db.Column(db.Integer, default=0) 19 20 class UserAddress(db.Model): 21 """ 使用者的地址 """ 22 __tablename__ = 'weibo_user_addr' 23 id = db.Column(db.Integer, primary_key=True) 24 addr = db.Column(db.String(256), nullable=False) 25 user_id = db.Column(db.Integer, db.ForeignKey('weibo_user.id'), nullable=False) #使用db.ForeignKey()進行外來鍵關聯 26 user = db.relationship('User', backref=db.backref('address', lazy=True)) #這一行程式碼不會在weibo_user_addr這張表裡面增加一列,它的作用就是為了方便我們操作模型的時候去訪問去查詢 27 # 使用db.relationship()進行反向引用。反向關聯誰呢,關聯User模型;建立一個反向引用backref=db.backref(),反向引用給誰呢,給address這個名字自己定義,lazy=True就是我們查詢到我們使用者物件的時候,不直接把他下面所有的地址列表給他查出來,當我們去訪問的時候,訪問下面地址列表的時候再給他查出來 28 29 ''' 30 接著上面程式碼舉個例子進一步解釋說明反向引用: 31 UserAddress裡面有個反向引用,引用的誰呢,引用的User 32 33 場景一: 34 user = User() #得到某一個使用者張三,想知道張三下面所有得地址列表怎麼辦? 35 user.address #透過user.address就可以獲取到到UserAddress這個模型了,就可以找到張三下面得所有地址列表,即地址表內容 36 37 場景二: 38 假設我們查到了某一個地址,也就是UserAddress模型對應資料庫的內容 39 addr = UserAddress() #根據地址如何去查使用者表的資訊呢? 40 addr.user #透過addr.user 就得到了User模型的物件,也就是user表物件 41 ''' 42 43 44 45 @app.route('/') 46 def mine(): 47 """ 首頁 """ 48 return render_template('index.html')
3.3.使用ORM插入、修改、刪除資料
繼續上面程式碼和使用者表、地址表闡述
新增/修改資料
- 構造ORM模型物件: user = User('admin','admin@example.com') 。在模型類User裡面傳遞一些引數:使用者名稱、密碼、使用者id等等即user表資料內容,構造一個user物件
- 新增到db.session,session可以理解為一個會話(備註:session裡面可新增多個物件): db.session.add(user) ,可以多次呼叫add傳遞多個物件
- 提交到資料庫: db.session.commit ,透過commit就完成了在使用者表裡面新增一條使用者記錄
新增資料例項:
修改資料例項:
物理刪除資料:資料記錄在表中直接刪掉
- 透過query.filter_by()查詢ORM模型物件: user=User.query.filter_by(username='王五').first() ,透過query.filter_by找到User模型中使用者叫王五的資料,first取第一條
- 新增到db.session,注意這個地方是delete不是add: db.session.delete(user)
- 提交變更到資料庫: db.session.commit
物理刪除資料例項:
邏輯刪除:相當於軟刪除,在表中新增一個狀態位,比如isvalid欄位,用於標記該記錄是否刪除(0:刪除,1:未刪除),其實表中資料記錄還在的。
3.4.使用ORM進行資料查詢與展示
繼續上面程式碼和使用者表、地址表闡述
ORM查詢
ORM查詢返回的是一個結果集,可以把它看成list。注意:當模型沒有使用__tablename__命名錶名,那麼表名就是模型名即類的名字。
篩選/獲取ORM返回結果集:
- 查詢模型(表)所有資料query.all(): User.query.all()
- 按條件查詢
- query.filter_by(): User.query.filter_by(username='張三')
- query.filter(): User.query.filter(User.nickname.endswith('五')).all()
- 可以使用filter()進行一些複雜的查詢,:如nickname.endswith() 表中nickname欄位是什麼結尾的、上面all()是將查詢出來的結果全部返回。
對ORM返回結果進行操作:
- 排序query.order_by(): User.query.order_by(User.username)
- 查詢TOP10的資料 query.limit(): User.query.limit(10).all()
返回單個ORM物件即查詢結果只有一條資料
- 根據主鍵(primary_key)值查詢: User.query.get(1)
- 獲取第一條記錄first(): User.query.first()
同時還有一些常用的檢視快捷函式:
- 返回的資料有則返回,無則返回404
- first() vs first_or_404()
- get() vs get_or_404()
- 多表關聯查詢
- 方式一:db.session.query(User).join(Address)
- 方式二:User.query.join(Address)
- 分頁(offset/limit)
- 方式一:.offset(offset)
- 方式二:.limit(limit)
- offset和limit使用方法和在mysql中使用一致
- 分頁(paginate):query物件提供的paginate函式進行分頁。 .paginate(page=2,per_page=4) #page當前在第幾頁,per_page每一頁多少條,返回的是一個Pagination的物件 。返回的Pagination物件擁有的屬性和函式如下?
- has_prev/has_next :是否有上一頁/下一頁
- items :當前頁的資料列表
- prev_num/next_num :上一頁/下一頁的頁碼
- total :總記錄數
- pages :總頁數
paginate例項練習:
1)準備資料
2)分頁: list_user.paginate(page2,per_page=4)
3)在模板中實現分頁操作
1 '''***app.py***''' 2 3 from flask import Flask, render_template 4 from flask_sqlalchemy import SQLAlchemy 5 6 app = Flask(__name__) 7 # 配置資料庫的連線引數 8 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:**@******/test_flask' 9 db = SQLAlchemy(app) 10 11 12 class User(db.Model): 13 __tablename__ = 'weibo_user' 14 id = db.Column(db.Integer, primary_key=True) 15 username = db.Column(db.String(64), nullable=False) 16 password = db.Column(db.String(256), nullable=False) 17 birth_date = db.Column(db.Date, nullable=True) 18 age = db.Column(db.Integer, default=0) 19 20 21 class UserAddress(db.Model): 22 """ 使用者的地址 """ 23 __tablename__ = 'weibo_user_addr' 24 id = db.Column(db.Integer, primary_key=True) 25 addr = db.Column(db.String(256), nullable=False) 26 user_id = db.Column(db.Integer, db.ForeignKey('weibo_user.id'), nullable=False) 27 user = db.relationship('User', backref=db.backref('address', lazy=True)) 28 29 30 @app.route('/') 31 def mine(): 32 """ 首頁 """ 33 return render_template('index.html') 34 35 36 @app.route('/user/<int:page>/') 37 def list_user(page): 38 """ 使用者分頁 """ 39 per_page = 10 # 每一頁的資料大小 40 # 1. 查詢使用者資訊 41 user_ls = User.query 42 # 2. 準備分頁的資料 43 user_page_data = user_ls.paginate(page, per_page=per_page) 44 return render_template('list_user.html', user_page_data=user_page_data)
1 <!-- ***list_user.html*** --> 2 3 <!DOCTYPE html> 4 <html lang="en"> 5 <head> 6 <meta charset="UTF-8"> 7 <title>使用者分頁操作</title> 8 </head> 9 <body> 10 <h3>總共有{{ user_page_data.total }}使用者,當前在第{{ user_page_data.page }}頁使用者, 總共{{ user_page_data.pages }}頁</h3> 11 <p> 12 使用者列表: 13 14 <ul> 15 {% for user in user_page_data.items %} 16 <li>{{ user.username }} - {{ user.password }}</li> 17 {% endfor %} 18 </ul> 19 {% if user_page_data.has_prev %} 20 <a href="{{ url_for('list_user', page=user_page_data.prev_num) }}">上一頁</a> 21 {% endif %} 22 {% if user_page_data.has_next %} 23 <a href="{{ url_for('list_user', page=user_page_data.next_num) }}">下一頁</a> 24 {% endif %} 25 </p> 26 </body> 27 </html>
思考:
透過本篇ORM學習,實現了可以將模型資料透過檢視傳遞給模板進行展示。那麼模板html如何透過檢視對模型中的資料進行增刪改查?詳見下一篇筆記:Flask表單的實現