Flask:Flask-SQLAlchemy
1 Flask-SQLAlchemy和Flask-Migrate 组件介绍
Flask-SQLAlchemy
是一个为 Flask 应用增加 SQLAlchemy 支持的扩展。它致力于简化在 Flask 中 SQLAlchemy 的使用。
Flask-migrate
是基于Alembic
的一个封装,并集成到Flask
中。所有的迁移操作都是Alembic
做的,能跟踪模型的变化,并将变化映射到数据库中。
Flask2.0
中已经移除了_compat
这个模块,与Flask-Script
不再兼容,取而代之的是Flask内置的cli库
,替代了这个manager的命令行管理机制。
之前的Flask_migrate
源码是支持Flask-Script
的,如果不想做此更新,可以指定安装库的版本继续下去:
Flask==1.1.4
Flask-Script==2.0.6
Flask-Migrate==2.5.3
Flask-SQLAlchemy==2.3.2
SQLAlchemy==1.3.24
如果Flask
版本在2.0以上,不必再使用flask_script
这个库,需把flask_migrate
库升级到3.0.0以上或最新版本,执行命令有所区别:
# 旧用法
python manager.py db init
python manager.py db migrate
python manager.py db upgrade
# 新用法
flask db init
flask db migrate
flask db upgrade
2 Flask-SQLAlchemy和Flask-Migrate 组件使用
flask-sqlalchemy
组件封装了sqlalchemy
,简化sqlalchemy
在flask框架中的使用;flask-migrate
组件用来扩展flask框架执行数据库迁移命令。
我们通过一个flask框架项目,了解flask-sqlalchemy
和flask-migrate
组件的使用:
目录结构
settings.py
在项目根目录下建立配置文件,sqlalchemy的配置和项目其他配置
from redis import Redis
class BaseConfig(object):
DEBUG = True
SESSION_TYPE = 'redis' # session类型为redis
SESSION_REDIS = Redis(host='127.0.0.1', port=6379) # redis连接
SESSION_KEY_PREFIX = 'session' # 保存到redis中值的前缀
SESSION_PERMANENT = True # 如果设置为False,关闭浏览器session失效
SESSION_USE_SIGNER = False # 是否对发送到浏览器上的session:cookie值进行加密
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123@127.0.0.1:3306/test?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
SQLALCHEMY_TRACK_MODIFICATIONS = False # 追踪对象的修改并发送信号
class ProductionConfig(BaseConfig):
pass
class DevelopmentConfig(BaseConfig):
pass
class TestingConfig(BaseConfig):
pass
exts.py
用来初始化得到Sqlalchemy实例db,做成单例,防止循环导入
from flask_sqlalchemy import SQLAlchemy
# 得到一个db对象,flask_sqlalchemy对原生SQLAlchemy做了封装,db.session相当于原生session,并处理了线程安全
db = SQLAlchemy()
manage.py
在项目根目录下建立项目启动文件
from sansa import create_app
from exts import db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
app = create_app()
# flask-script的操作,支持命令python manage.py runserver启动项目
manager = Manager(app)
# flask-migrate的操作,它基于flask-script,需要联合使用,第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
Migrate(app, db)
# manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令,相当于自定制脚本命令,支持python manage.py db init
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
__init.py__
在项目sansa包内的init文件,用来初始化得到Flask实例app,并把db注册到app中
from flask import Flask
from exts import db
from .views import account
def create_app():
app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')
# 将db注册到app中,因为app中有sqlalchemy的配置,拿到配置可以构造engine,构造session对象,封装到db对象中
db.init_app(app)
# 注册蓝图
app.register_blueprint(account.account)
return app
models.py
在项目sansa包内的数据库文件,flask-sqlalchemy
进行了封装,用db对象创建表模型,执行数据库迁移命令即可创建表、删除表、修改表
from exts import db
class Users(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return '<User %s>' % self.username
用原生SQLAlchemy
创建表,需要4个步骤
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index # 1 导入字段属性
Base = declarative_base() #2 造一个所有模型类的基类,相当于django ORM的models.Model类
class Users(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=False)
email = Column(String(32), unique=True)
def init_db():
# 3 创建engine对象
engine = create_engine(
"mysql+pymysql://root:123@127.0.0.1:3306/test?charset=utf8",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 4 通过engine对象创建表,创建出被Base管理的所有表
Base.metadata.create_all(engine)
account.py
views包下的视图文件,用db.session操作数据库的增删改查
from flask import Blueprint
from exts import db
from .. import models
account = Blueprint('account', __name__)
@account.route('/login')
def login():
db.session.add(models.Users(username='lqz', email='123@qq.com'))
db.session.commit()
# 添加示例
"""
db.session.add(models.Users(username='lqz', pwd='123', gender=1))
db.seesion.commit()
obj = db.session.query(models.Users).filter(models.Users.id == 1).first()
print(obj)
PS: db.session 和 db.create_session
"""
user_list = db.session.query(models.Users).all()
db.session.close()
for item in user_list:
print(item.username)
return 'login'
使用数据库迁移命令
python3 manage.py db init # 初始化环境,只用执行一次,创建migrations文件夹
python3 manage.py db migrate # 自动检测模型,生成迁移脚本,在migrations文件夹生成记录; 等同于django ORM的 python3 manage.py makemigrations
python3 manage.py db upgrade # 将迁移脚本映射到数据库中,等同于django ORM的 python3 manage.py migrate
python3 manage.py db --help # 查看更多命令
python3 manage.py db downgrade 版本号 # 回退数据库
补充
由于Python3.8不再支持time.clock
,time.clock() 函数以浮点数计算的秒数返回当前的CPU时间。使用flask-sqlalchemy时会报错“_timer = time.clock AttributeError: module ‘time‘ has no attribute ‘clock‘” 解决方法:修改flask-sqlalchemy源码__init__.py
# the best timer function for the platform
if sys.platform == 'win32':
# _timer = time.clock
_timer = time.perf_counter
else:
_timer = time.time