Flask 操作Mysql資料庫 - flask-sqlalchemy擴充套件
資料庫的設定
Web應用中普遍使用的是關係模型的資料庫,關係型資料庫把所有的資料都儲存在表中,表用來給應用的實體建模,表的列數是固定的,行數是可變的。它使用結構化的查詢語言。關係型資料庫的列定義了表中表示的實體的資料屬性。比如:商品表裡有name、price、number等。 Flask本身不限定資料庫的選擇,你可以選擇SQL或NOSQL的任何一種。也可以選擇更方便的SQLALchemy,類似於Django的ORM。SQLALchemy實際上是對資料庫的抽象,讓開發者不用直接和SQL語句打交道,而是通過Python物件來操作資料庫,在捨棄一些效能開銷的同時,換來的是開發效率的較大提升。
SQLAlchemy是一個關係型資料庫框架,它提供了高層的ORM和底層的原生資料庫的操作。flask-sqlalchemy是一個簡化了SQLAlchemy操作的flask擴充套件。
下面使用mysql作為示例進行說明。
建立mysql資料庫
1.登入資料庫
mysql -u root -p password
2.建立資料庫,並設定編碼
create database <資料庫名> charset=utf8;
3.顯示所有資料庫
show databases;
4.執行
create database flask_test charset=utf8;
安裝flask-sqlalchemy的擴充套件
pip install -U Flask-SQLAlchemy
python2:要連線mysql資料庫,仍需要安裝flask-mysqldb
pip install flask-mysqldb
python3:要連線mysql資料庫,仍需要安裝pymysql
pip install pymysql
本篇章內容以python3作為開講。
使用Flask-SQLAlchemy連線mysql資料庫
使用Flask-SQLAlchemy擴充套件操作資料庫,首先需要建立資料庫連線。資料庫連線通過URL指定,而且程式使用的資料庫必須儲存到Flask配置物件的SQLALCHEMY_DATABASE_URI鍵中。
對比下Django和Flask中的資料庫設定:
Django的資料庫設定:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改後端資料庫使用mysql 'NAME': 'mydb', # 設定訪問資料庫名稱 'USER': 'root', # 訪問訪問mysql使用者名稱 'PASSWORD': 'password', # 設定訪問密碼 'HOST': 'localhost', # 設定訪問ip地址 'PORT': 3306, # 設定訪問埠號 } }
Flask的資料庫設定:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user:[email protected]:3306/database'
常用的SQLAlchemy欄位型別
上面看完了如何設定連線資料庫,那麼來看看,使用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中,插入、修改、刪除操作,均由資料庫會話管理。會話用db.session表示。在準備把資料寫入資料庫前,要先將資料新增到會話中然後呼叫commit()方法提交會話。
資料庫會話是為了保證資料的一致性,避免因部分更新導致資料不一致。提交操作把會話物件全部寫入資料庫,如果寫入過程發生錯誤,整個會話都會失效。
資料庫會話也可以回滾,通過db.session.rollback()方法,實現會話提交資料前的狀態。
在Flask-SQLAlchemy中,查詢操作是通過query物件操作資料。最基本的查詢是返回表中所有資料,可以通過過濾器進行更精確的資料庫查詢。
下面先來建立兩個表的資料模型:使用者表和角色表。
在檢視函式中定義模型類
看完了上面那麼多的概念說明,下面來看看如何建立資料模型以及建立資料表,如下:
1.在指令碼15_SQLAlchemy.py編寫建立User和Role資料模型
from flask import Flask from flask_sqlalchemy import SQLAlchemy import pymysql pymysql.install_as_MySQLdb() app = Flask(__name__) class Config(object): """配置引數""" # 設定連線資料庫的URL user = 'root' password = '********' database = 'flask_test' app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://%s:%[email protected]:3306/%s' % (user,password,database) # 設定sqlalchemy自動更跟蹤資料庫 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查詢時會顯示原始SQL語句 app.config['SQLALCHEMY_ECHO'] = True # 禁止自動提交資料處理 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = False # 讀取配置 app.config.from_object(Config) # 建立資料庫sqlalchemy工具物件 db = SQLAlchemy(app) class Role(db.Model): # 定義表名 __tablename__ = 'roles' # 定義欄位 id = db.Column(db.Integer, primary_key=True,autoincrement=True) name = db.Column(db.String(64), unique=True) users = db.relationship('User',backref='role') # 反推與role關聯的多個User模型物件 class User(db.Model): # 定義表名 __tablename__ = 'users' # 定義欄位 id = db.Column(db.Integer, primary_key=True,autoincrement=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')) # 設定外來鍵 if __name__ == '__main__': # 刪除所有表 db.drop_all() # 建立所有表 db.create_all()
- 執行指令碼,建立資料庫
python3 15_SQLAlchemy.py
3.在mysql檢視已經建立的表結構
+--------------------+ | Tables_in_flask_ex | +--------------------+ | roles | | users | +--------------------+ 2 rows in set (0.00 sec) mysql> mysql> desc users; +---------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(64) | YES | UNI | NULL | | | email | varchar(64) | YES | UNI | NULL | | | pswd | varchar(64) | YES | | NULL | | | role_id | int(11) | YES | MUL | NULL | | +---------+-------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec) mysql> mysql> desc roles; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(64) | YES | UNI | NULL | | +-------+-------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql>
建立好了資料表之後,下面來看看如何執行資料的增刪查改的。
常用的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物件,它包含指定範圍內的結果 |
建立表:
db.create_all()
刪除表
db.drop_all()
每次插入單條資料
if __name__ == '__main__': # 插入一條角色資料 role1 = Role(name='admin') db.session.add(role1) db.session.commit() # 再次插入一條資料 role2 = Role(name='user') db.session.add(role2) db.session.commit()
執行指令碼:
python3 15_SQLAlchemy.py
在mysql中檢視插入的資料,如下:
mysql> select * from roles \G *************************** 1. row *************************** id: 1 name: admin *************************** 2. row *************************** id: 2 name: user 2 rows in set (0.00 sec)
一次插入多條資料
# 一次性插入多條資料 user1 = User(name='wang',email='[email protected]',pswd='123456',role_id=role1.id) user2 = User(name='zhang',email='[email protected]',pswd='201512',role_id=role2.id) user3 = User(name='chen',email='[email protected]',pswd='987654',role_id=role2.id) user4 = User(name='zhou',email='[email protected]',pswd='456789',role_id=role1.id) db.session.add_all([user1,user2,user3,user4]) db.session.commit()
執行插入資料,如下:
python3 15_SQLAlchemy.py
在mysql中查詢插入的資料如下:
mysql> select * from users \G *************************** 1. row *************************** id: 1 name: wang email: [email protected] pswd: 123456 role_id: 1 *************************** 2. row *************************** id: 2 name: zhang email: [email protected] pswd: 201512 role_id: 2 *************************** 3. row *************************** id: 3 name: chen email: [email protected] pswd: 987654 role_id: 2 *************************** 4. row *************************** id: 4 name: zhou email: [email protected] pswd: 456789 role_id: 1 4 rows in set (0.00 sec) mysql>
雖然這裡在python中看上去是一次性插入多條資料,其實在mysql也是執行多行插入的語句,通過mysql的日誌可以看到如下:
2019-11-23T16:48:56.984459Z 9061 Query INSERT INTO users (name, email, pswd, role_id) VALUES ('wang', '[email protected]', '123456', 1) 2019-11-23T16:48:56.997132Z 9061 Query INSERT INTO users (name, email, pswd, role_id) VALUES ('zhang', '[email protected]', '201512', 2) 2019-11-23T16:48:57.010175Z 9061 Query INSERT INTO users (name, email, pswd, role_id) VALUES ('chen', '[email protected]', '987654', 2) 2019-11-23T16:48:57.024134Z 9061 Query INSERT INTO users (name, email, pswd, role_id) VALUES ('zhou', '[email protected]', '456789', 1)
實際上並沒有將多個values合併到一個insert語句,依然是多個insert語句逐個插入的。
查詢:filter_by精確查詢
返回名字等於'wang'的所有user
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(1)
邏輯非,返回名字不等於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的角色 role1 = Role.query.get(1) #查詢該角色的所有使用者 role1.users
關聯查詢使用者所屬角色:
#查詢users表id為3的使用者 user1 = User.query.get(3) #查詢使用者屬於什麼角色 user1.role
參考連結: https://www.jianshu.com/p/7e32074e4fad https://juejin.cn/post/6844904030892900366