Flask 連接和操作Mysql數據庫


Flask 操作Mysql數據庫 - flask-sqlalchemy擴展

官網文檔

flask-sqlalchemy.palletsprojects.com/en/master/q…

數據庫的設置

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.執行如下

mysql> create database flask_ex charset=utf8;
Query OK, 1 row affected (0.06 sec)
復制代碼

安裝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://root:mysql@127.0.0.1:3306/flask_ex'
復制代碼

常用的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_ex'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://%s:%s@127.0.0.1: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查看已經創建的表結構

mysql> show tables;
+--------------------+
| 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='wang@163.com',pswd='123456',role_id=role1.id)
    user2 = User(name='zhang',email='zhang@189.com',pswd='201512',role_id=role2.id)
    user3 = User(name='chen',email='chen@126.com',pswd='987654',role_id=role2.id)
    user4 = User(name='zhou',email='zhou@163.com',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: wang@163.com
   pswd: 123456
role_id: 1
*************************** 2. row ***************************
     id: 2
   name: zhang
  email: zhang@189.com
   pswd: 201512
role_id: 2
*************************** 3. row ***************************
     id: 3
   name: chen
  email: chen@126.com
   pswd: 987654
role_id: 2
*************************** 4. row ***************************
     id: 4
   name: zhou
  email: zhou@163.com
   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', 'wang@163.com', '123456', 1)
2019-11-23T16:48:56.997132Z	 9061 Query	INSERT INTO users (name, email, pswd, role_id) VALUES ('zhang', 'zhang@189.com', '201512', 2)
2019-11-23T16:48:57.010175Z	 9061 Query	INSERT INTO users (name, email, pswd, role_id) VALUES ('chen', 'chen@126.com', '987654', 2)
2019-11-23T16:48:57.024134Z	 9061 Query	INSERT INTO users (name, email, pswd, role_id) VALUES ('zhou', 'zhou@163.com', '456789', 1)
復制代碼

實際上並沒有將多個values合並到一個insert語句,依然是多個insert語句逐個插入的。

查詢:filter_by精確查詢

返回名字等於wang的所有user

User.query.filter_by(name='wang').all()
復制代碼

在交互模型執行如下:

>python3 db_demo.py shell
In [1]: from db_demo import User

In [2]: User.query.filter_by(name='wang').all()
Out[2]: [<User 1>]

In [3]:
復制代碼

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

User.query.first()
復制代碼

執行如下:

In [3]: User.query.first()
Out[3]: <User 1>
復制代碼

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

User.query.all()
復制代碼

執行如下:

In [4]: User.query.all()
Out[4]: [<User 1>, <User 2>, <User 3>, <User 4>]

In [5]:
復制代碼

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

User.query.filter(User.name.endswith('g')).all()
復制代碼

執行如下:

In [5]: User.query.filter(User.name.endswith('g')).all()
Out[5]: [<User 1>, <User 2>]
復制代碼

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

User.query.get()
復制代碼

執行如下:

In [6]: User.query.get(2)
Out[6]: <User 2>

In [7]: user2 = User.query.get(2)

In [8]: user2.name
Out[8]: 'zhang'
復制代碼

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

User.query.filter(User.name!='wang').all()
復制代碼

執行如下:

In [9]: User.query.filter(User.name!='wang').all()
Out[9]: [<User 2>, <User 3>, <User 4>]
復制代碼

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

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

執行如下:

In [10]: from sqlalchemy import and_

In [15]: users = User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

In [16]: for user in users:
    ...:     print(user.email)
    ...:
zhou@163.com
復制代碼

邏輯或,需要導入or_

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

執行如下:

In [17]: from sqlalchemy import or_

In [18]: users = User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

In [19]: for user in users:
    ...:     print(user.name, user.email)
    ...:
wang wang@163.com
zhang zhang@189.com
chen chen@126.com
zhou zhou@163.com

In [20]:
復制代碼

not_ 相當於取反

from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()
復制代碼

執行如下:

In [22]: from sqlalchemy import not_

In [25]: users = User.query.filter(not_(User.name=='chen')).all()

In [26]: for user in users:
    ...:     print(user.name, user.email)
    ...:
wang wang@163.com
zhang zhang@189.com
zhou zhou@163.com
復制代碼

查詢數據后刪除

user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()
復制代碼

執行如下:

(venv) $ >python3 db_demo.py shell

In [1]: from db_demo import User

In [3]: user = User.query.first()

In [5]: from db_demo import db

In [6]: db.session.delete(user)

In [7]: db.session.commit()

In [8]: User.query.all()
Out[8]: [<User 2>, <User 3>, <User 4>]
復制代碼

更新數據

user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()
復制代碼

執行如下:

In [1]: from db_demo import User

In [5]: from db_demo import db

In [9]: user = User.query.first()

In [10]: user
Out[10]: <User 2>

In [11]: user.name
Out[11]: 'zhang'

In [12]: user.name = 'dong'

In [13]: db.session.commit()

In [14]: user = User.query.first()

In [15]: user.name
Out[15]: 'dong'
復制代碼

使用update

User.query.filter_by(name='zhang').update({'name':'li'})
復制代碼

執行如下:

In [21]: User.query.filter_by(name='dong').update({'name':'li'})
Out[21]: 0

In [22]: User.query.get(2)
Out[22]: <User 2>

In [23]: user = User.query.get(2)

In [24]: user.name
Out[24]: 'li'
復制代碼

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

關聯查詢角色的所有用戶:

#查詢roles表id為1的角色
role1 = Role.query.get(1)
#查詢該角色的所有用戶
role1.users
復制代碼

執行如下:

In [25]: from db_demo import Role

In [26]: role1 = Role.query.get(1)

In [27]: role1.users
Out[27]: [<User 4>]

In [28]: role2 = Role.query.get(2)

In [29]: role2.users
Out[29]: [<User 2>, <User 3>]
復制代碼

關聯查詢用戶所屬角色:

#查詢users表id為3的用戶
user1 = User.query.get(3)
#查詢用戶屬於什么角色
user1.role
復制代碼

執行如下:

In [30]: user1 = User.query.get(3)

In [31]: user1.role
Out[31]: <Role 2>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM