当前位置: 首页 > 科技观察

菜鸟五分钟学Python玩转SQL的神器!

时间:2023-03-21 17:06:16 科技观察

背??景其实一开始我用的是pymysql,但是发现维护起来比较麻烦,还有代码注入的风险,所以索性直接用了ORM框架。ORM全称ObjectRelationalMapper,可以简单理解为数据库表和Python类之间的映射。通过操作Python类,可以间接操作数据库。Python的ORM框架比较有名的有SQLAlchemy和Peewee。这里不做对比,只是简单说明一下个人对SQLAlchemy的一些使用,希望能给朋友们带来帮助。sqlalchemyversion:1.3.15pymysqlversion:0.9.3mysqlversion:5.7初始化工作一般使用ORM框架,会有一些初始化工作,比如数据库连接,定义基本映射等,以MySQL为例,你只需要需要传入DSN字符串来创建数据库连接。其中echo表示是否输出相应的SQL语句,有助于调试。fromsqlalchemyimportcreate_engineengine=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.pymappingdeclaration(Modelintroduction)比如我们有这样一个测试表createtablepy_orm(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'uniqueid',`name`varchar(255)NOTNULLDEFAULT''COMMENT'name',`attr`JSONNOTNULLCOMMENT'attribute',`ct`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'createdtime',`ut`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONupdateCURRENT_TIMESTAMPCOMMENT'updatedtime',PRIMARYKEY(`id`))ENGINE=InnoDBCOMMENT'测试表';在ORM框架中,映射的结果是下面的Python类整数,autoincrement=True,primary_key=True,comment='uniqueid')name=Column(String(255),nullable=False,default='',comment='name')attr=Column(JSON,nullable=False,评论='属性')ct=Column(TIMESTAMP,nullable=False,server_default=text('CURRENT_TIMESTAMP'),comment='创建时间')ut=Column(TIMESTAMP,nullable=False,server_default=text('CURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP'),comment='更新时间')首先,我们可以看到PyOrmModel继承了Base类,这是sqlalchemy提供的一个基类。它会对我们声明的Python类做一些检查,我会把它放在base_model中"mysql+pymysql://root:123456@127.0.0.1:33306/orm_test?charset=utf8mb4",echo=False)其次,每个Python类都必须包含__tablename__属性,否则找不到对应的表。三、创建数据表有两种方式。第一种当然是在MySQL中手动创建。只要你的Python类定义没有问题,就可以正常运行;二是通过orm框架创建,比如如下:#main.py#注意这里的导入路径。Base在创建表的时候,会寻找继承它的子类。如果路径错误,将无法创建成功。fromsqlachlemy_labimportBase,engineif__name__=='__main__':Base.metadata.create_all(engine)创建效果:...2020-04-0410:12:53,974INFOsqlalchemy.engine.base.EngineCREATETABLEpy_orm(idINTEGERNOTNULLAUTO_INCREMENT,nameVARCHAR(255)NOTNULLDEFAULT''COMMENT'name',attrJSONNOTNULLCOMMENT'property',ctTIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP,utTIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP更新CURRENT_TIMESTAMP,PRIMARYKEY(id))四、关于字段属性1.primary_key和autoincrement比较好理解,是MySQL的主键和自增属性。2、如果是int类型,则不需要指定长度,如果是varchar类型,则必须指定。3.Nullable对应MySQL中的NULL和NOTNULL4.关于default和server_default:default表示ORM框架层面的默认值,即如果插入时字段没有赋值,我们定义的默认值为用过的;server_default表示数据库级别的默认值,即DDL语句中的default关键字。Session的介绍在SQLAlchemy的文档中有提到,对数据库的增删改查都是通过session进行的。>>>fromsqlalchemy.ormimportsessionmaker>>>Session=sessionmaker(bind=engine)>>>session=Session()>>>orm=PyOrmModel(id=1,name='test',attr={})>>>session.add(orm)>>>session.commit()>>>session.close()由上可知,对于每一个操作,我们都需要获取、提交和释放session。这样就太多余了,也太麻烦了,所以我们一般都会进行一层封装。1、使用contextmanager处理session的异常回滚和关闭。这部分与引用的文章几乎一致。#base_model.pyfromcontextlibimportcontextmanagerfromsqlalchemy.ormimportsessionmaker,scoped_sessiondef_get_session():"""Getsession"""returnscoped_session(sessionmaker(bind=engine,expire_on_commit=False))()#这里统一session管理,包括get,提交,回滚和关闭@contextmanagerdefdb_session(commit=True):session=_get_session()try:yieldsessionifcommit:session.commit()exceptExceptionase:session.rollback()raiseefinally:ifsession:session.to_json(model):fields=PyOrmModel.fields()json_data={}forfieldinfields:json_data[field]=model.__getattribute__(field)返回json_data@staticmethoddeffrom_json(data:dict):fields=PyOrmModel.fields()模型=PyOrmModel()对于字段中的字段:如果数据中的字段:model.__setattr__(field,data[field])返回model3。数据库操作的封装,不像参考文章,我直接调用了session,这样调用者就不需要关注model层,降低耦合#py_orm_model_op.pyfromsqlachlemy_lab.modelimportdb_sessionfromsqlachlemy_lab.modelimportPyOrmModelclassPyOrmModelOp:def__init__(self):pass@staticmethoddefsave_data(data:dict):withdb_session()assession:model=PyOrmModel.from_json(data)会话。add(model)#查询操作,不需要commit@staticmethoddefquery_data(pid:int):data_list=[]withdb_session(commit=False)assession:data=session.query(PyOrmModel).filter(PyOrmModel.id==pid)fordindata:data_list.append(PyOrmModel.to_json(d))returndata_list4.调用方法#main.pyfromsqlachlemy_lab.model_opimportPyOrmModelOpif__name__=='__main__':PyOrmModelOp.save_data({'id':1,'name':'test','attr':{}})完整代码请参见:https://github.com/yangancode/python_lab/tree/master/sqlachlemy_lab

最新推荐
猜你喜欢