之前研究了一段时间的Flask,觉得使用ORM操作数据库真滴爽,于是便去翻了翻SQLAlchemy模块的文档。一开始还想着是不是要从table类开始写,看了一眼数据库里的一百多张表,顿时感觉压力山大......
好在SQLAlchemy可以使用命令生成表类,如下:
# 依赖sqlacodegen模块
# pip install sqlacodegen -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
# 使用前可以先sqlacodegen –help看一下具体用法
# 一句话生成models.py文件
# sqlacodegen mysql+oursql://user:password@localhost/dbname
# 数据表反向生成sqlalchemy ORM:
# sqlacodegen --tables tablename(表名) --outfile ./filename.py(输出的文件名) mysql+pymysql://user:password@host/dbname?charset=yourencode
# windows 环境下cmd窗口 执行 即可.(注意输出的文件)
但这样操作仍然有些不方便,尤其是在数据表经常发生变化的时候,每次都要去同步数据表结构,感觉就很麻烦。
虽然数据库里有一百多张表,但笔者经常用的表也就十多个,总有一种杀鸡焉用牛刀的感觉,个人也还是更喜欢pymysql那样的连接方式。
好在SQLAlchemy也提供了反射ORM的方法--automap_base。
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine
# 连接url
client_url = f'mysql+pymysql://user:password@host:port/dbname?charset=yourencode'
# 连接引擎
engine = create_engine(client_url, pool_size=10)
# 生成所有的映射关系为Base
Base = automap_base()
# 设置被映射的类和关系并执行映射
Base.prepare(engine, reflect=True)
# 获取会话连接
session = Session(bind=engine)
# 获取表对象
table = Base.classes.table_name
接下来就可以用ORM方式操作数据库了。
# select 全表查询
datas = session.query(table).all()
# insert 插入记录
user = table(username='xxx', password='xxx')
session.add(user)
session.commit()
# update 更新记录
session.query(table).filter_by(username='xxx').update({'password':'xxxxxx'})
session.commit()
# delete 删除记录
session.query(table).filter_by(username='xxx').delete()
session.commit()
还可以根据自己的需求进一步封装api。
首先,先将上述操作写入到类中。
class SqlAlchemyScript:
def __init__(self, host='xx.xx.xx.xx', user='xxxx', passwd='xxxxxx', port=3306, db='xx', charset='UTF8MB4'):
self.host = host
self.user = user
self.passwd = passwd
self.port = port
self.db = db
self.charset = charset
# 数据库连接url
self.client_url = f'mysql+pymysql://{self.user}:{self.passwd}@{self.host}:{self.port}/{self.db}?charset={self.charset}&autocommit=true'
# 数据库连接引擎
self.engine = create_engine(self.client_url, pool_size=5)
# 生成所有的映射关系为Base
self.Base = automap_base()
# 设置被映射的类和关系并执行映射
self.Base.prepare(self.engine, reflect=True)
# 获取会话连接
self.session = Session(bind=self.engine)
在这个类中定义2个获取表对象的方法。get_table方法获取单独的表,get_tables方法获取列表中的所有表并返回1个包含所有表对象的列表。
def get_table(self, table_name):
"""
获取表对象
:param table_name: 表名
:return: table
"""
if isinstance(table_name, str):
strs = f'self.Base.classes.{table_name}'
# 反射得到ORM
table = eval(strs)
return table
else:
raise TypeError('传入的类型必须是str!!!')
def get_tables(self, tables):
"""
获取表对象
:param tables: 存储表名的列表或元组
:return: list
"""
lst = list()
if isinstance(tables, list) or isinstance(tables, tuple):
for t in tables:
table_obj = self.get_table(t)
lst.append(table_obj)
else:
raise TypeError('传入的类型必须是list or tuple!!!')
return lst
接下来可以封装任意你想使用的功能。
比如:定义1个简单插入方法。
def simple_insert(self, table, data_dict):
"""
插入记录
:param table: 表对象
:param data_dict: 插入的数据(dcit)
:return: 新插入的实例
"""
result = table(**data_dict)
self.session.add(result)
self.session.commit()
print(f'{data_dict} 已插入表!!!')
return result
使用方法如下:
if __name__ == '__main__':
test = SqlAlchemyScript()
table = test.get_table('table_name')
result = test.simple_insert(table, {'username': 'xxx', 'password': 'xxx'})
print(f'新插入了1条记录,该记录的id为:{result.id}')