1. 程式人生 > 實用技巧 >Flask-SQLAlchemy 的基本使用

Flask-SQLAlchemy 的基本使用

Flask-SQLAlchemy 的基本使用

SQLAlchemy是一個關係型資料庫框架,它提供了高層的 ORM 和底層的原生資料庫的操作。flask-sqlalchemy 是一個簡化了 SQLAlchemy 操作的flask擴充套件。

安裝

  • 安裝 flask-sqlalchemy
pip install flask-sqlalchemy
  • 如果連線的是 mysql 資料庫,需要安裝 mysqldb
pip install flask-mysqldb

資料庫連線設定

  • 在 Flask-SQLAlchemy 中,資料庫使用URL指定,而且程式使用的資料庫必須儲存到Flask配置物件的 SQLALCHEMY_DATABASE_URI
    鍵中
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
  • 其他設定:
# 動態追蹤修改設定,如未設定只會提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查詢時會顯示原始SQL語句
app.config['SQLALCHEMY_ECHO'] = True
  • 其他配置
名字 備註
SQLALCHEMY_DATABASE_URI 用於連線的資料庫 URI 。例如:sqlite:tmp/test.dbmysql://username:password@server/db
SQLALCHEMY_BINDS 一個對映 binds 到連線 URI 的字典。更多 binds 的資訊見用 Binds 操作多個數據庫
SQLALCHEMY_ECHO 如果設定為Ture, SQLAlchemy 會記錄所有 發給 stderr 的語句,這對除錯有用。(列印sql語句)
SQLALCHEMY_RECORD_QUERIES 可以用於顯式地禁用或啟用查詢記錄。查詢記錄 在除錯或測試模式自動啟用。更多資訊見get_debug_queries()。
SQLALCHEMY_NATIVE_UNICODE 可以用於顯式禁用原生 unicode 支援。當使用 不合適的指定無編碼的資料庫預設值時,這對於 一些資料庫介面卡是必須的(比如 Ubuntu 上 某些版本的 PostgreSQL )。
SQLALCHEMY_POOL_SIZE 資料庫連線池的大小。預設是引擎預設值(通常 是 5 )
SQLALCHEMY_POOL_TIMEOUT 設定連線池的連線超時時間。預設是 10 。
SQLALCHEMY_POOL_RECYCLE 多少秒後自動回收連線。這對 MySQL 是必要的, 它預設移除閒置多於 8 小時的連線。注意如果 使用了 MySQL , Flask-SQLALchemy 自動設定 這個值為 2 小時。

連線其他資料庫

完整連線 URI 列表請跳轉到 SQLAlchemy 下面的文件 (Supported Databases) 。這裡給出一些 常見的連線字串。

  • Postgres:
postgresql://scott:tiger@localhost/mydatabase
  • MySQL:
mysql://scott:tiger@localhost/mydatabase
  • Oracle:
- oracle://scott:[email protected]:1521/sidname
  • SQLite (注意開頭的四個斜線):
sqlite:absolute/path/to/foo.db

常用的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中無法自行決定時,指定多對多關係中的二級聯結條件

在檢視函式中定義模型類

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
 
 
app = Flask(__name__)
 
#設定連線資料庫的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/test'
 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查詢時會顯示原始SQL語句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
 
class Role(db.Model):
    # 定義表名
    __tablename__ = 'roles'
    # 定義列物件
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    us = db.relationship('User', backref='role')
 
    #repr()方法顯示一個可讀字串
    def __repr__(self):
        return 'Role:%s'% self.name
 
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)
    email = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
 
    def __repr__(self):
        return 'User:%s'%self.name
if __name__ == '__main__':
    app.run(debug=True)

模型之間的關聯

一對多

class Role(db.Model):
    ...
    #關鍵程式碼
    us = db.relationship('User', backref='role', lazy='dynamic')
    ...
class User(db.Model):
    ...
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
  • 其中realtionship描述了Role和User的關係。在此文中,第一個引數為對應參照的類“User”
  • 第二個引數backref為類User申明新屬性的方法
  • 第三個引數lazy決定了什麼時候SQLALchemy從資料庫中載入資料
    • 如果設定為子查詢方式(subquery),則會在載入完Role物件後,就立即載入與其關聯的物件,這樣會讓總查詢數量減少,但如果返回的條目數量很多,就會比較慢
      • 設定為 subquery 的話,role.users 返回所有資料列表
    • 另外,也可以設定為動態方式(dynamic),這樣關聯物件會在被使用的時候再進行載入,並且在返回前進行過濾,如果返回的物件數很多,或者未來會變得很多,那最好採用這種方式
      • 設定為 dynamic 的話,role.users 返回查詢物件,並沒有做真正的查詢,可以利用查詢物件做其他邏輯,比如:先排序再返回結果

多對多

registrations = db.Table('registrations',  
    db.Column('student_id', db.Integer, db.ForeignKey('students.id')),  
    db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))  
)  
class Course(db.Model):
    ...
class Student(db.Model):
    ...
    courses = db.relationship('Course',secondary=registrations,  
                                    backref='students',  
                                    lazy='dynamic')

常用的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()

插入一條資料

ro1 = Role(name='admin')
db.session.add(ro1)
db.session.commit()

查詢:filter_by精確查詢

返回名字等於wang的所有人

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()

邏輯非,返回名字不等於wang的所有資料

User.query.filter(User.name!='wang').all()

not_ 相當於取反

from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).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()

查詢資料後刪除

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()

關聯查詢示例:

角色和使用者的關係是一對多的關係,一個角色可以有多個使用者,一個使用者只能屬於一個角色。

  • 查詢角色的所有使用者
 #查詢roles表id為1的角色ro1 = Role.query.get(1)
 #查詢該角色的所有使用者ro1.us.all()
  • 查詢使用者所屬角色
#查詢users表id為3的使用者us1 = User.query.get(3)
#查詢使用者屬於什麼角色us1.role

資料庫遷移

首先要在虛擬環境中安裝Flask-Migrate。

pip install flask-migrate
  • 程式碼檔案內容:
#coding=utf-8
from flask import Flask
 
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager
 
app = Flask(__name__)
manager = Manager(app)
 
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/Flask_test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
 
#第一個引數是Flask的例項,第二個引數是Sqlalchemy資料庫例項
migrate = Migrate(app,db) 
 
#manager是Flask-Script的例項,這條語句在flask-Script中新增一個db命令
manager.add_command('db',MigrateCommand)
 
#定義模型Role
class Role(db.Model):
    # 定義表名
    __tablename__ = 'roles'
    # 定義列物件
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    user = db.relationship('User', backref='role')
 
    #repr()方法顯示一個可讀字串,
    def __repr__(self):
        return 'Role:'.format(self.name)
 
#定義使用者
class User(db.Model):
    __talbe__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    #設定外來鍵
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
 
    def __repr__(self):
        return 'User:'.format(self.username)
 
 
if __name__ == '__main__':
    manager.run()

建立遷移倉庫

#這個命令會建立migrations資料夾,所有遷移檔案都放在裡面。
python database.py db init

建立遷移指令碼

  • 自動建立遷移指令碼有兩個函式
    • upgrade():函式把遷移中的改動應用到資料庫中。
    • downgrade():函式則將改動刪除。
  • 自動建立的遷移指令碼會根據模型定義和資料庫當前狀態的差異,生成upgrade()和downgrade()函式的內容。
  • 對比不一定完全正確,有可能會遺漏一些細節,需要進行檢查
python database.py db migrate -m 'initial migration'

更新資料庫

python database.py db upgrade

返回以前的版本

可以根據history命令找到版本號,然後傳給downgrade命令:

python app.py db history
輸出格式:<base> ->  版本號 (head), initial migration
  • 回滾到指定版本
python app.py db downgrade 版本號

實際操作順序:

  • 1.python 檔案 db init
  • 2.python 檔案 db migrate -m“版本名(註釋)”
  • 3.python 檔案 db upgrade 然後觀察表結構
  • 4.根據需求修改模型
  • 5.python 檔案 db migrate -m“新版本名(註釋)”
  • 6.python 檔案 db upgrade 然後觀察表結構
  • 7.若返回版本,則利用 python 檔案 db history檢視版本號
  • 8.python 檔案 db downgrade(upgrade) 版本號