ORM框架
ORM提供了一种持久化模式,可以高效地对数据库进行访问。ORM的英文是Object Relation Mapping,中文叫做对象关系映射。是RDBMS和业务实体对象之间的一个映射,把底层的RDBMS封装成业务实体对象,提供给业务逻辑层使用。
ORM可以兼容多种DBMS,但是会在性能上有一些损失,而且对于一些复杂的数据查询,直接编写SQL反而会更简单有效。
Python中的ORM框架有哪些
Python有三种主流的ORM框架:
- Django,它是Python的web应用开发框架。采用了MTV的框架模式。
一个Model映射到一个数据表
- SQLAlchemy,他也是Python中常用的ORM框架之一。提供了SQL工具包以及ORM工具。
- peewee,轻量级的ORM框架,简单易用。采用了Model类、Field实例和Model实例来于数据库建立映射关系,从而完成面向对象的管理方式。
使用SQLAlchemy来操作MySQL
安装相应的工具包
pip install sqlalchemy初始化数据库连接from sqlalchemy import create_engine# 初始化数据库连接,修改为你的数据库用户名和密码engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/wucai')
创建模型
# 定义Player对象: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))
__tablename__指明了模型对应的数据表名称,即player数据表。同时在player模型中对采用的变量名进行定义,变量名需要和数据表中的字段名称保持一致,否则找不到数据表中的字段。
在SQLAlchemy中,采用Column对字段进行定义
Column的参数,可以对对象创建列约束
对数据表进行增删改查
示例
- 给player表增加一个新球员,姓名为“约翰科林斯”,球队ID未1003,身高为2.08
# 创建DBSession类型:DBSession = sessionmaker(bind=engine)# 创建session对象:session = DBSession()# 创建Player对象:new_player = Player(team_id = 1003, player_name = "约翰-科林斯", height = 2.08)# 添加到session:session.add(new_player)# 提交即保存到数据库:session.commit()# 关闭session:session.close()
首先初始化DBSession,相当于创建一个数据库的会话示例session。通过session来完成新球员的添加。
然后把创建好的对象new_player添加到session中,提交到数据库即可完成添加数据的操作。
查询数据
示例
- 查询身高>=2.08m的球员
#增加to_dict()方法到Base类中def to_dict(self): return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}#将对象可以转化为dict类型Base.to_dict = to_dict# 查询身高>=2.08的球员有哪些rows = session.query(Player).filter(Player.height >= 2.08).all()print([row.to_dict() for row in rows])
运行结果
[{'player_id': 10003, 'team_id': 1001, 'player_name': '安德烈-德拉蒙德', 'height': Decimal('2.1100000000')}, {'player_id': 10004, 'team_id': 1001, 'player_name': '索恩-马克', 'height': Decimal('2.1600000000')}, {'player_id': 10009, 'team_id': 1001, 'player_name': '扎扎-帕楚里亚', 'height': Decimal('2.1100000000')}, {'player_id': 10010, 'team_id': 1001, 'player_name': '乔恩-洛伊尔', 'height': Decimal('2.0800000000')}, {'player_id': 10011, 'team_id': 1001, 'player_name': '布雷克-格里芬', 'height': Decimal('2.0800000000')}, {'player_id': 10015, 'team_id': 1001, 'player_name': '亨利-埃伦森', 'height': Decimal('2.1100000000')}, {'player_id': 10023, 'team_id': 1002, 'player_name': '多曼塔斯-萨博尼斯', 'height': Decimal('2.1100000000')}, {'player_id': 10024, 'team_id': 1002, 'player_name': '迈尔斯-特纳', 'height': Decimal('2.1100000000')}, {'player_id': 10032, 'team_id': 1002, 'player_name': 'TJ-利夫', 'height': Decimal('2.0800000000')}, {'player_id': 10033, 'team_id': 1002, 'player_name': '凯尔-奥奎因', 'height': Decimal('2.0800000000')}, {'player_id': 10037, 'team_id': 1002, 'player_name': '伊凯·阿尼博古', 'height': Decimal('2.0800000000')}, {'player_id': 10038, 'team_id': 1003, 'player_name': '约翰-科林斯', 'height': Decimal('2.0800000000')}]
如果对整个数据行进行查询,采用的是session.query(Player),相当于使用的是SELECT *。
在进行查询的时候,使用的是filter方法,对应的是SQL中的WHERE条件查询。
如果是AND的关系,如查询身高>=2.08,同时身高<=2.10的球员
rows = session.query(Player).filter(Player.height >=2.08, Player.height <=2.10).all()
使用了SQLAlchemy的or_操作符,使用之前要引入,即from sqlalchemy import or_
除了多条件查询,SQLAlchemy也支持分组查询、排序和返回指定数量的结果
示例
- 按照team_id进行分组,同时筛选分组后数据行数大于5的分组,并且按照分组后数据行数递增的顺序进行排序,显示team_id字段,以及每个分组的数据行数。
from sqlalchemy import funcrows = 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()print(rows)
运行结果
[(1001, 20), (1002, 17)]
注意事项:
- 把需要显示的字段Player.team_id,func.count(Player.player_id)作为query的参数,要用到sqlalchemy的func类,它提供了各种聚集函数。
- 在query()后面使用了group_by()进行分组,参数设置为Player.team_id字段,再使用having对分组条件进行筛选,参数func.count(Player.player_id)>5
- 使用order_by进行排序,参数为func.count(Player.player_id).asc(),也就是按照分组后的数据行数递增的顺序进行排序,最后使用.all()方法需要返回全部的数据。
删除数据
示例
- 删除姓名为约翰科林斯的球员
row = session.query(Player).filter(Player.player_name=='约翰-科林斯').first()session.delete(row)session.commit()session.close()
注:判断球员是否为约翰科林斯,需要使用(==)
修改数据
示例
- 修改球员索恩马克的身高改成2.17
row = session.query(Player).filter(Player.player_name=='索恩-马克').first()row.height = 2.17session.commit()session.close()
总结