18丨SQLAlchemy:如何使用Python ORM框架来操作MySQL?
该思维导图由 AI 生成,仅供参考
我们为什么要使用 ORM 框架?
- 深入了解
- 翻译
- 解释
- 总结
SQLAlchemy是一个Python ORM框架,本文介绍了如何使用SQLAlchemy来操作MySQL数据库。ORM框架的作用是将数据库中的数据映射为对象,提供了一种高效的数据库访问方式。文章首先解释了为什么要使用ORM框架,指出随着项目规模增大,直接编写SQL语句会增加维护成本,而ORM框架可以将注意力集中在业务逻辑层面。然后介绍了Python中常用的ORM框架,包括Django、SQLAlchemy和peewee,重点介绍了SQLAlchemy的特点和使用方法。接着详细讲解了如何使用SQLAlchemy对MySQL数据库进行增删改查操作,包括初始化数据库连接、创建模型和对数据表进行操作。最后,文章总结了ORM框架的优缺点,指出在实际工作中需要根据需求选择适合的方式。整体而言,本文通过清晰的示例和详细的讲解,使读者能够快速了解ORM框架的作用和使用方法,为使用Python操作MySQL数据库提供了有益的指导。 SQLAlalchemy工具的使用并不复杂,只需掌握一些使用方法,尤其是创建seesion对象和通过session对象完成对数据的增删改查等操作。文章还提到了ORM的价值和不足,以及建议在项目代码量增加时采用ORM框架。最后,读者被鼓励在评论区分享答案和交流。
《SQL 必知必会》,新⼈⾸单¥68
全部留言(29)
- 最新
- 精选
- 墨禾以下从ORM的作用,是什么,优缺点以及一些比较流行的ORM的对比的个人总结: 1.ORM的作用 对象关系映射,能够直接将数据库对象进行持久化。 在没有ORM前,我们要自己写数据库连接方法,自己在方法里面嵌入原生的sql语句去访问数据表…… 这时问题就来了: 数据库名,数据表名完全暴露在代码中,有脱库的风险; 需要我们自己处理数据表对象,比如说把数据表中取出的数据转化为标准json等,sql语句安全过滤,数据表、字段别名、兼容多种数据库等一系列的数据处理工作; 下面介绍一下ORM到底是啥? 2、ORM是什么? ORM作为数据库层与业务逻辑层之间的一个抽象,能够将业务逻辑的处理持久化为内存对象,交由数据库去处理。其封装了数据库的连接,数据表的操作细节……在文中我们可以看到ORM将sql语句做了封装,我们可以通过filter实现过滤,而不是写where子句。 ORM真的那么好? 3、优缺点 优点: 安全:因为屏蔽了数据库的具体操作细节以及对sql做了严格的过滤,因此能够保证数据库信息的隐蔽性,同时防止sql注入。 简单:屏蔽了数据层的访问细节,我们只需要集中注意力处理业务逻辑就可以了。 缺点: 性能低:自动化意味着加载很多即使没有必要的关联和映射,牺牲性能。但ORM也采取了一些补救措施:对象懒加载,缓存技术等。 学习成本高:面向对象的封装设计,是的我们必须要去了解对象的处理细节。 难以实现复杂查询:ORM实现的是一些通用的数据处理方法,一些负责的业务处理还是需要自己组装sql。 那么还有哪些比较流行的ORM呢? hibernate:强调对单条数据的处理 mybits:基于自定义配置的sql操作
作者回复: 整理的不错 大家都可以看下
2019-07-2334 - JustDoDT缺少一些代码,可以参考廖雪峰的这个。 https://www.liaoxuefeng.com/wiki/1016959663602400/1017803857459008
作者回复: 多谢分享
2019-07-22321 - 一叶知秋日常交作业~~~ # -*- coding:utf-8 -*- from sqlalchemy import and_ from sqlalchemy import Column, INT, FLOAT, VARCHAR from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Test_db: def __init__(self): """此处填上自己的连接配置""" self.engine = create_engine( 'mysql+pymysql://UserName:Password@host:port/Db_Name?charset=utf8') db_session = sessionmaker(bind=self.engine) self.session = db_session() def update(self, target_class, query_filter, target_obj): """ 更新操作通用方法 :param target_class: 表对象 :param query_filter: 查询条件 :param target_obj: 更新目标对象 :return: """ try: self.session.query(target_class).filter(query_filter).update(target_obj) self.session.commit() self.session.close() return True except Exception as e: print(e) class Player(Base): """定义表结构""" __tablename__ = 'player' player_id = Column(INT(), primary_key=True) team_id = Column(INT()) player_name = Column(VARCHAR(255)) height = Column(FLOAT()) def __init__(self, player_id, team_id, player_name, height): self.player_id = player_id self.team_id = team_id self.player_name = player_name self.height = height if __name__ == '__main__': db_obj = Test_db() query_filter = and_(Player.height == 2.08) target_obj = {'height': 2.09} update_result = db_obj.update(Player, query_filter, target_obj) 后续更新数量、更新结果等等判断就略过了... (小声bb:什么时候极客时间评论也能支持markdown啊。。)
作者回复: 赞下完成作业的同学
2019-07-2212 - ABC翻了一下SQLAlchemy的官方文档,看到一个简单的办法,作业如下: ''' 作业: 使用SQLAlchemy工具查询身高为2.08米的球员,并且将这些球员的身高修改为2.09; 参考: https://docs.sqlalchemy.org/en/13/core/dml.html ''' from sqlalchemy import Column, String, Integer, Float,create_engine,update from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() engine = create_engine('mysql+mysqlconnector://root:123456@localhost:3306/geektime-sql') class Player(Base): __tablename__ = 'player' player_id = Column(Integer, primary_key=True, autoincrement=True) team_id = Column(Integer) player_name = Column(String(255)) height = Column(Float(3,2)) def to_dict(self): return {c.name: getattr(self, c.name, None) for c in self.__table__.columns} if __name__ == '__main__': DBSession = sessionmaker(bind=engine) session = DBSession() Base.to_dict = to_dict print("更新前:") rows = session.query(Player).filter(Player.height == 2.08).all() print([row.to_dict() for row in rows]) # 参考: https://docs.sqlalchemy.org/en/13/core/dml.html#sqlalchemy.sql.expression.update stmt = update(Player).where(Player.height == 2.08).values(height=2.09) engine.execute(stmt) session.commit() rows = session.query(Player).filter(Player.height == 2.09).all() print("更新后:") print([row.to_dict() for row in rows]) session.close() 太长,省略了部分执行结果.自己执行一下,就可以看到完整结果了.. 更新前: [{'player_id': 10010, 'team_id': 1001, 'player_name': '乔恩-洛伊尔', 'height': Decimal('2.0800000000')}...... 更新后: [{'player_id': 10010, 'team_id': 1001, 'player_name': '乔恩-洛伊尔', 'height': Decimal('2.0900000000')}...... [Finished in 0.9s]
作者回复: Good Job
2019-07-229 - 夜路破晓框架对实体的映射不难理解,数据库本身就是对现实世界的映射,借由映射将事实转换为数据. 代码部分有些基础的也不难理解;基础较弱硬钢的亲们,耐心一条条来缕也可以捋顺,都是基础的东西,无非花费时间长短问题.有几个坑这里记录下,供后来人借鉴: 1.关于初始化连接数据库问题.creat_engine的参数这块容易卡壳,可以参考以下文字说明: create_engine("数据库类型+数据库驱动://数据库用户名:数据库密码@IP地址:端口/数据库",其他参数) 2.数据库驱动这块,老师的参考代码是用mysqlconnector,沿承得是上篇中导入mysql-connector包;网上一些资料以及参考其他同学的答案有使用pymysql,要用这个需安装pip install pymysql.这两货对于本篇的学习内容在本质上是一样的,任选一个即可. 3.在代码复写过程中,删除操作一直报错.网上查了资料说是跟返回值有关.经过测试,发现问题所在,filter返回结果为None.也就是说没有查询到"约翰-科林斯".往回倒腾,发现开始新增数据那里,增加的" 约翰-科林斯 ",前后对比后者两侧多了个空格.统一前后,删除操作顺利完成.
作者回复: 总结的不错
2019-07-228 - JustDoDT错误解决: 如果报如下错误:Authentication plugin 'caching_sha2_password' is not supported sqlalchemy.exc.NotSupportedError: (mysql.connector.errors.NotSupportedError) Authentication plugin 'caching_sha2_password' is not supported (Background on this error at: http://sqlalche.me/e/tw8g) 可以参考下面的链接处理: https://stackoverflow.com/questions/51783313/how-do-i-get-sqlalchemy-create-engine-with-mysqlconnector-to-connect-using-mysql
作者回复: 多谢分享
2019-07-225 - jxs1211老师,我的表中有个时间字段,我想在插入数据时,自动生成时间应怎么设置该字段,是这样吗: `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
作者回复: 可以的 设置个默认值
2019-07-253 - taoistfrom sqlalchemy import create_engine, Column, Integer, String, Float from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() engine = create_engine("mysql+pymysql://root:toor@localhost:3306/test") Session = sessionmaker(bind=engine) def to_dict(self): return {c.name: getattr(self, c.name, None) for c in self.__table__.columns} Base.to_dict = to_dict class Player(Base): __tablename__ = "player" player_id = Column(Integer, primary_key=True, autoincrement=True) team_id = Column(Integer) player_name = Column(String(255)) height = Column(Float(3, 2)) session = Session() rows = session.query(Player).filter(Player.height == 2.08).all() for row in rows: print(row.to_dict()) row.height = 2.09 session.commit() # 验证 rows = session.query(Player).filter(Player.height == 2.09).all() print([row.to_dict() for row in rows]) session.close()
作者回复: Good Job
2019-12-232 - 阿锋上面那个分组查询,按照分组后数据行数递增的顺序进行排序,怎么结果是[(1001, 20), (1002, 17)],那不是递减?是不是写错了?
作者回复: rows = session.query(Player.team_id, func.count(Player.player_id)).group_by(Player.team_id).having(func.count(Player.player_id)>5).order_by(func.count(Player.player_id).asc()).all() 这里使用的是asc(),所以结果应该是:[(1002, 17), (1001, 20)],你可以再check下order_by的部分
2019-07-222 - Geek_5d805bto_dict方法这块看不太懂,base类指的是player类吗,谁给讲讲
作者回复: 可以看下评论中同学留言
2019-07-2521