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-sqlalchemyflask-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

 

posted @ 2022-10-13 23:20  不会钓鱼的猫  阅读(1966)  评论(0编辑  收藏  举报