您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

一个超方便使用SQL的Python神器!

2024/3/17 7:05:34发布21次查看
背景其实一开始用的是pymysql,但是发现维护比较麻烦,还存在代码注入的风险,所以就干脆直接用orm框架。
orm即object relational mapper,可以简单理解为数据库表和python类之间的映射,通过操作python类,可以间接操作数据库。
python的orm框架比较出名的是sqlalchemy和peewee,这里不做比较,只是单纯讲解个人对sqlalchemy的一些使用,希望能给各位朋友带来帮助。
sqlalchemy版本: 1.3.15 pymysql版本: 0.9.3 mysql版本: 5.7初始化工作一般使用orm框架,都会有一些初始化工作,比如数据库连接,定义基础映射等。
以mysql为例,创建数据库连接只需要传入dsn字符串即可。其中echo表示是否输出对应的sql语句,对调试比较有帮助。
from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://$user:$password@$host:$port/$db?charset=utf8mb4', echo=true)
个人设计对于我个人而言,引进orm框架时,我的项目会参考mvc模式做以下设计。其中model存储的是一些数据库模型,即数据库表映射的python类;model_op存储的是每个模型对应的操作,即增删查改;调用方(如main.py)执行数据库操作时,只需要调用model_op层,并不用关心model层,从而实现解耦。
├── main.py ├── model │ ├── __init__.py │ ├── base_model.py │ ├── ddl.sql │ └── py_orm_model.py └── model_op ├── __init__.py └── py_orm_model_op.py
映射声明(model介绍)举个栗子,如果我们有这样一张测试表。
create table py_orm ( `id` int(11) not null auto_increment comment '唯一id', `name` varchar(255) not null default '' comment '名称', `attr` json not null comment '属性', `ct` timestamp not null default current_timestamp comment '创建时间', `ut` timestamp not null default current_timestamp on update current_timestamp comment '更新时间', primary key(`id`) )engine=innodb comment '测试表';
在orm框架中,映射的结果就是下文这个python类。
# py_orm_model.py from .base_model import base from sqlalchemy import column, integer, string, timestamp, text, json class pyormmodel(base): __tablename__ = 'py_orm' id = column(integer, autoincrement=true, primary_key=true, comment='唯一id') name = column(string(255), nullable=false, default='', comment='名称') attr = column(json, nullable=false, comment='属性') ct = column(timestamp, nullable=false, server_default=text('current_timestamp'), comment='创建时间') ut = column(timestamp, nullable=false, server_default=text('current_timestamp on update current_timestamp'), comment='更新时间')
首先,我们可以看到pyormmodel继承了base类,该类是sqlalchemy提供的一个基类,会对我们声明的python类做一些检查,我将其放在base_model中。
# base_model.py # 一般base_model做的都是一些初始化的工作 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base base = declarative_base() engine = create_engine(mysql+pymysql://root:123456@127.0.0.1:33306/orm_test?charset=utf8mb4, echo=false)
其次,每个python类都必须包含__tablename__属性,不然无法找到对应的表。
第三,关于数据表的创建有两种方式,第一种当然是手动在mysql中创建,只要你的python类定义没有问题,就可以正常操作;第二种是通过orm框架创建,比如下面。
# main.py # 注意这里的导入路径,base创建表时会寻找继承它的子类,如果路径不对,则无法创建成功 from sqlachlemy_lab import base, engine if __name__ == '__main__': base.metadata.create_all(engine)
创建效果:
... 2020-04-04 10:12:53,974 info sqlalchemy.engine.base.engine create table py_orm ( id integer not null auto_increment, name varchar(255) not null default '' comment '名称', attr json not null comment '属性', ct timestamp not null default current_timestamp, ut timestamp not null default current_timestamp on update current_timestamp, primary key (id) )
第四,关于字段属性:
1.primary_key和autoincrement比较好理解,就是mysql的主键和递增属性。
2.如果是int类型,不需要指定长度,而如果是varchar类型,则必须指定。
3.nullable对应的就是mysql中的null 和 not null
4.关于default和server_default: default代表的是orm框架层面的默认值,即插入的时候如果该字段未赋值,则会使用我们定义的默认值;server_default代表的是数据库层面的默认值,即ddl语句中的default关键字。
session介绍在sqlalchemy的文档中提到,数据库的增删查改是通过session来执行的。
>>> from sqlalchemy.orm import sessionmaker >>> session = sessionmaker(bind=engine) >>> session = session() >>> orm = pyormmodel(id=1, name='test', attr={}) >>> session.add(orm) >>> session.commit() >>> session.close()
如上,我们可以看到,对于每一次操作,我们都需要对session进行获取,提交和释放。这样未免过于冗余和麻烦,所以我们一般会进行一层封装。
1.采用上下文管理器的方式,处理session的异常回滚和关闭,这部分与所参考的文章是几乎一致的。
# base_model.py from contextlib import contextmanager from sqlalchemy.orm import sessionmaker, scoped_session def _get_session(): 获取session return scoped_session(sessionmaker(bind=engine, expire_on_commit=false))() # 在这里对session进行统一管理,包括获取,提交,回滚和关闭 @contextmanager def db_session(commit=true): session = _get_session() try: yield session if commit: session.commit() except exception as e: session.rollback() raise e finally: if session: session.close()
2.在pyormmodel中增加两个方法,用于model和dict之间的转换。
class pyormmodel(base): ... @staticmethod def fields(): return ['id', 'name', 'attr'] @staticmethod def to_json(model): fields = pyormmodel.fields() json_data = {} for field in fields: json_data[field] = model.__getattribute__(field) return json_data @staticmethod def from_json(data: dict): fields = pyormmodel.fields() model = pyormmodel() for field in fields: if field in data: model.__setattr__(field, data[field]) return model
3.数据库操作的封装,与参考的文章不同,我是直接调用了session,从而使调用方不需要关注model层,减少耦合。
# py_orm_model_op.py from sqlachlemy_lab.model import db_session from sqlachlemy_lab.model import pyormmodel class pyormmodelop: def __init__(self): pass @staticmethod def save_data(data: dict): with db_session() as session: model = pyormmodel.from_json(data) session.add(model) # 查询操作,不需要commit @staticmethod def query_data(pid: int): data_list = [] with db_session(commit=false) as session: data = session.query(pyormmodel).filter(pyormmodel.id == pid) for d in data: data_list.append(pyormmodel.to_json(d)) return data_list
4.调用方:
# main.py from sqlachlemy_lab.model_op import pyormmodelop if __name__ == '__main__': pyormmodelop.save_data({'id': 1, 'name': 'test', 'attr': {}})
以上就是一个超方便使用sql的python神器!的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product