1. 程式人生 > 資料庫 >Flask 操作Mysql資料庫 - flask-sqlalchemy擴充套件

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()
  1. 執行指令碼,建立資料庫
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