SQL 必知必会
陈旸
清华大学计算机博士
73337 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
第一章:SQL语法基础篇 (19讲)
SQL 必知必会
15
15
1.0x
00:00/00:00
登录|注册

18丨SQLAlchemy:如何使用Python ORM框架来操作MySQL?

分组操作、排序和返回指定数量的结果
多条件查询
修改数据
删除数据
查询数据
增加数据
数据类型和参数
定义Player对象
简单易用
轻量级的ORM框架
活跃的社区
SQL工具包及ORM工具
Model模型
MTV框架模式
练习题
建议
实现并不复杂
对数据表进行增删改查
创建模型
初始化数据库连接
peewee
SQLAlachemy
Django
优点和缺点
ORM的作用
持久化层的作用
总结
如何使用SQLAlchemy来操作MySQL
Python中的ORM框架都有哪些
什么是ORM框架,以及为什么要使用ORM框架?
SQLAlachemy

该思维导图由 AI 生成,仅供参考

上节课,我介绍了 Python DB API 规范的作用,以及如何使用 MySQL 官方的 mysql-connector 驱动来完成数据库的连接和使用。在项目比较小的时候,我们可以直接使用 SQL 语句,通过 mysql-connector 完成与 MySQL 的交互,但是任何事物都有两面性,随着项目规模的增加,代码会越来越复杂,维护的成本也越来越高,这时 mysql-connector 就不够用了,我们需要更好的设计模式。
Python 还有另一种方式可以与 MySQL 进行交互,这种方式采用的是 ORM 框架。我们今天就来讲解如何使用 ORM 框架操作 MySQL,那么今天的课程你需要掌握以下几个方面的内容:
什么是 ORM 框架,以及为什么要使用 ORM 框架?
Python 中的 ORM 框架都有哪些?
如何使用 SQLAlchemy 来完成与 MySQL 的交互?

我们为什么要使用 ORM 框架?

在讲解 ORM 框架之前,我们需要先了解什么是持久化。如下图所示,持久化层在业务逻辑层和数据库层起到了衔接的作用,它可以将内存中的数据模型转化为存储模型,或者将存储模型转化为内存中的数据模型。
你可能会想到,我们在讲事务的 4 大特性 ACID 时,提到过持久性。你可以简单地理解为,持久性就是将对象数据永久存储在数据库中。通常我们将数据库的作用理解为永久存储,将内存理解为暂时存储。我们在程序的层面操作数据,其实都是把数据放到内存中进行处理,如果需要数据就会通过持久化层,从数据库中取数据;如果需要保存数据,就是将对象数据通过持久化层存储到数据库中。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

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-23
    34
  • JustDoDT
    缺少一些代码,可以参考廖雪峰的这个。 https://www.liaoxuefeng.com/wiki/1016959663602400/1017803857459008

    作者回复: 多谢分享

    2019-07-22
    3
    21
  • 一叶知秋
    日常交作业~~~ # -*- 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-22
    12
  • 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-22
    9
  • 夜路破晓
    框架对实体的映射不难理解,数据库本身就是对现实世界的映射,借由映射将事实转换为数据. 代码部分有些基础的也不难理解;基础较弱硬钢的亲们,耐心一条条来缕也可以捋顺,都是基础的东西,无非花费时间长短问题.有几个坑这里记录下,供后来人借鉴: 1.关于初始化连接数据库问题.creat_engine的参数这块容易卡壳,可以参考以下文字说明: create_engine("数据库类型+数据库驱动://数据库用户名:数据库密码@IP地址:端口/数据库",其他参数) 2.数据库驱动这块,老师的参考代码是用mysqlconnector,沿承得是上篇中导入mysql-connector包;网上一些资料以及参考其他同学的答案有使用pymysql,要用这个需安装pip install pymysql.这两货对于本篇的学习内容在本质上是一样的,任选一个即可. 3.在代码复写过程中,删除操作一直报错.网上查了资料说是跟返回值有关.经过测试,发现问题所在,filter返回结果为None.也就是说没有查询到"约翰-科林斯".往回倒腾,发现开始新增数据那里,增加的" 约翰-科林斯 ",前后对比后者两侧多了个空格.统一前后,删除操作顺利完成.

    作者回复: 总结的不错

    2019-07-22
    8
  • 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-22
    5
  • jxs1211
    老师,我的表中有个时间字段,我想在插入数据时,自动生成时间应怎么设置该字段,是这样吗: `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

    作者回复: 可以的 设置个默认值

    2019-07-25
    3
  • taoist
    from 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-23
    2
  • 阿锋
    上面那个分组查询,按照分组后数据行数递增的顺序进行排序,怎么结果是[(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-22
    2
  • Geek_5d805b
    to_dict方法这块看不太懂,base类指的是player类吗,谁给讲讲

    作者回复: 可以看下评论中同学留言

    2019-07-25
    2
    1
收起评论
显示
设置
留言
29
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部