在作项目的过程当中,咱们都遇到过,常常须要修改咱们数据库的字段,在flask中,是经过ORM(对象关系映射)来建立数据库的,表—>model class,字段---->属性python
在flask中,咱们是经过第三方插件SQLAlchemy来建立数据库表,采用的是db.create_all()方法,这样,在咱们修改数据库的Model的字段以后,想要同步数据库,就只能经过删除表,而后从新调用db.create_all()来完成。
因此,flask引入了flask_script 和 flask_migrate(pip install)来解决这个问题:
一. 新建db_init.py 文件, 初始化db
from flask_sqlalchemy import SQLAlchemy
# 初始化db
db = SQLAlchemy()
二. flask app.py文件中使用db
from db_init import db
# db中激活app
db.init_app(app)
with app.app_context():
# 创建表结构
db.create_all()
三. 新建manager.py文件,编写以下:app
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import create_app
from db_init import db
from models import user, finance_item
# 初始化app
app = create_app()
manager = Manager(app)
# 要使用flask-migrate,必须先绑定db和app
Migrate(app, db)
# 将MigrateCommand添加到manager中,"db"是自定义命令
manager.add_command('db', MigrateCommand)
# 参考文章
# http://www.javashuo.com/article/p-xmqzgplm-hw.html
#
if __name__ == '__main__':
manager.run()
四. 环境中激活, 迁移, 更新数据库
项目更目录下, 进入terminal, 输入以下命令
python manager.py db init
# 成功后, 在项目目录中会多出一个migration 的文件夹
# 迁移数据库, 这里可以做到数据表字段的增加删除等等
python manager.py db migrate
# 迁移后, 做更新操作
python manager.py db upgrade
五. SQLAlchemy Model的书写
import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from db_init import db
class BaseDB:
"""
数据基础类
"""
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
create_time = db.Column(db.DATETIME(6), default=datetime.datetime.now)
update_time = db.Column(db.DATETIME(6), default=datetime.datetime.now, onupdate=datetime.datetime.now)
# 是否被删除
is_delete = db.Column(db.BOOLEAN, default=False)
六. 单个Model的操作
在码脚本过程中, 发现操作数据库的时候, 接口需要写部分高度重复的代码, 试着写了通用的方法, 在接口简单数据库操作, 使用到的时候, 只传入对应的Model name, 就能做单表的增删改查.
# encoding:utf-8
# author: kyleyao
from flask import current_app
from sqlalchemy.exc import IntegrityError
from db_init import db
class DBOperation:
@staticmethod
def find_all(model_name) -> list:
"""
根据提供的数据库表model name查询所有的数据.
:param model_name: 数据库表名称
:return:
"""
items = None
try:
items = model_name.query.all()
except IntegrityError as e:
current_app.logger.error("got IntegrityError db error please check")
current_app.logger.error(e)
except Exception as e:
current_app.logger.error("got other db error please check")
current_app.logger.error(e)
finally:
return items
@staticmethod
def find_items_by(model_name, **kwargs) -> list:
"""
根据提供的数据库表model name, 以及查询条件, 查询所有匹配的数据.
:param model_name: 数据库表名称
:param kwargs: 查询字段 where id = 1, name = abc
:return: 一个 sqlalchemy model list
"""
items = None
try:
items = model_name.query.filter_by(**kwargs).all()
except IntegrityError as e:
current_app.logger.error("got IntegrityError db error please check")
current_app.logger.error(e)
except Exception as e:
current_app.logger.error("got other db error please check")
current_app.logger.error(e)
finally:
return items
@staticmethod
def find_first_by(model_name, **kwargs):
"""
根据提供的数据库表model name, 以及查询条件, 查询匹配到的第一条数据.
:param model_name: 数据库表名称
:param kwargs: 查询字段 where id = 1, name = abc
:return: 一个 sqlalchemy model
"""
item = None
try:
item = model_name.query.filter_by(**kwargs).first()
except IntegrityError as e:
current_app.logger.error("got IntegrityError db error please check")
current_app.logger.error(e)
except Exception as e:
current_app.logger.error("got other db error please check")
current_app.logger.error(e)
finally:
# print('*************************************')
# print(type(items))
# print(items)
return item
@staticmethod
def create_item(model_name, **kwargs) -> bool:
result = False
try:
new_to_db = model_name(**kwargs)
db.session.add(new_to_db)
db.session.commit()
result = True
except IntegrityError as e:
current_app.logger.error("got IntegrityError db error please check")
current_app.logger.error(e)
except Exception as e:
current_app.logger.error("got other db error please check")
current_app.logger.error(e)
finally:
return result
@staticmethod
def update_item(model_name, item_mark: dict, update_value: dict) -> bool:
"""
更新数据库item, 更新之前需要查询下数据存在不, 不存在直接返回更新失败.
:param model_name: 要更新的数据库名称
:param item_mark: 用于查找数据库数据的标志位
:param update_value: 需要更新的数据
:return:
"""
result = False
try:
if model_name.query.filter_by(**item_mark).first() is None:
current_app.logger.error(f"No items found by provided info: \t {item_mark}")
return result
model_name.query.filter_by(**item_mark).update(update_value)
db.session.commit()
result = True
except IntegrityError as e:
current_app.logger.error("got IntegrityError db error please check")
current_app.logger.error(e)
except Exception as e:
current_app.logger.error("got other db error please check")
current_app.logger.error(e)
finally:
return result
七. 一些简单的操作
- 多表查询, 排序, sql语句中and写法
# 多表查询指定数据时
db.session.query(Model_A.id, Model_A.name, Model_B.value).filter(
Model_A.id == Model_B.category_id,
and_(extract("year", Model_A.record_date) == '2022'),
and_(Model_A.is_delete == 0)).order_by(Model_A.record_date.desc(),
Model_A.create_time.desc()).all()
后续, 还涉及到多表联合查询, 这个还没有想明白. 要是有不正确的地方, 请指出, 谢谢.