# SQLAlchemy备忘录 **Published by:** [Untitled](https://paragraph.com/@0x9493695d028e374e8e462810b7f1836c3cdfb26e/) **Published on:** 2021-11-17 **URL:** https://paragraph.com/@0x9493695d028e374e8e462810b7f1836c3cdfb26e/sqlalchemy ## Content 前言 SQLALchemy是Python社区中著名的ORM库,由于本职工作是前端,Python相关技术栈不常用到,经常性的会造成遗忘,所以记下这篇文章,已备忘速查 以下代码演示环境为: 数据库: MySQL5.7 操作系统: Windows10 开发工具: PyCharm2019.3.2 Python3.8 安装 # 安装sqlalchemy pip install sqlalchemy # 安装对应的数据库驱动 pip install mysql-connector-python 引入对应的模块 from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import Column, String, Integer, Text, ForeignKey, create_engine from sqlalchemy.ext.declarative import declarative_base 连接数据库并创建session # 创建连接 engine = create_engine('mysql+mysqlconnector://<username>:<password>@<host>:<port>/<db>') # 创建会话类 Session = sessionmaker(bind=engine) # 创建会话 session = Session() 创建表的class定义 Base = declarative_base() class Vod(Base): # 表名 __tablename__ = 'vod' id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(200)) cover = Column(Text) intro = Column(Text) class Actor(Base): # 表名 __tablename__ = 'actor' id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(40)) avatar = Column(Text) 创建表(如果表已经存在,不会重新创建覆盖) Base.metadata.create_all(engine) 删除表 Base.metadata.drop_all(engine) 基本CRUD def get_vod(vid): return session.query(Vod).filter_by(id=vid).first() def insert_vod(vod): # add方法仅仅是新建,如果实例的主键值已经存在于表中,则会报错,不会去更新 session.add(vod) session.commit() return vod def delete_vod(vod): # 以一个实例对象为参数,通过主键字段来判断表中是否存在这条记录 session.delete(vod) session.commit() def update_vod(vod): # merge方法会通过主键值来判断当前实例是否存在于表中,如果存在,则更新; 否则新建 session.merge(vod) session.commit() # 或者先通过查询获取到需要更新的对象,然后更新这个对象并提交 my_vod = session.query(Vod).filter_by(id=vod.id).first() if my_vod: my_vod.name = vod.name session.commit() 创建多对多关系 创建多对多关系,需要通过中间表实现 class Vod2Actor(Base): # 表名 __tablename__ = 'vod2actor' id = Column(Integer, primary_key=True, autoincrement=True) vod_id = Column(Integer, ForeignKey('vod.id')) actor_id = Column(Integer, ForeignKey('actor.id')) 使用ForeignKey创建外键, 外键所在的表为子表,所以Vod2Actor为子表,Vod和Actor为父表ForeignKey接受一个字符串作为参数,参数为'<_*tablename_*>.' 创建relationship relationship是sqlalchemy.orm提供的对关系之间的一种便利调用方式。 创建relationship不是必须的。假设现在已知一个Vod.title的值,想要知道这个Vod.actors的值,如果不通过relationship,则需要这样操作 def get_actors_by_vod_title(title): vod = session.query(Vod).filter_by(title=title).first() if vod: vod2Actors = session.query(Vod2Actor).filter_by(vod_id=vod.id).all() actors = [session.query(Actor).filter_by(id=item.actor_id).first() for item in vod2Actors] return actors return None 如果在Vod中加上relationship, 则操作就会变得非常简单 class Vod(Base): # ...... # 第一个参数为类名,第二个secondary为中间表的表名 actors = relationship('Actor', secondary='vod2actor') def get_actors_by_vod_title_with_relationship(title): vod = session.query(Vod).filter_by(title=title).first() if vod: return vod.actors return None relationship还有一个backref参数,它提供了反向操作的能力, 当设置后, actor也可以直接查询与其对应的vods的值 class Vod(Base): # ...... # backref为一个字符串,设置后,actor便会多一个以这个字符串为名的属性 # 除了backref,还有一个back_populates, 两者功能一样,backref是back_populates的高级版,使用更简单方便 # backref只需单向声明,而back_populates则需要双向声明 # 以vod和actor为例,backref只需要在Vod或Actor其中一个的relationship中声明,而back_populates则需要在Vod和Actor的relationship中都声明 actors = relationship('Actor', secondary='vod2actor', backref='vods') def get_vods_by_actor_name_with_backref(name): actor = session.query(Actor).filter_by(name=name).first() if actor: return actor.vods return None 创建一对多关系 创建一对多关系,只需要在子表中设置外键, 外键的值为父表的主键值, 不需要额外建立中间表;多对多关系本质上就是通过两张表与中间表建立一对多关系实现的 class Vod(Base): # ... downloads = relationship('Download', backref="vod"); class Download(Base): # 表名 __tablename__ = 'download' id = Column(Integer, primary_key=True, autoincrement=True) url = Column(Text) # 迅雷/磁力/百度云 type = Column(Text(20)) vod_id = Column(Integer, ForeignKey('vod.id')) 创建一对一关系 创建一对一关系,和创建一对多关系方法一致,只是在通过relationship进行快捷操作时,需要设置uselist=False, 使play_bilibili不是一个列表 class Vod(Base): # ... # 默认uselist=True, 通过play_bilibili获取到的值是一个列表 play_bilibili = relationship('Play', uselist=False, backref='vod'); Demo源码 https://github.com/demo-box/sqlalchemy-demo.git ## Publication Information - [Untitled](https://paragraph.com/@0x9493695d028e374e8e462810b7f1836c3cdfb26e/): Publication homepage - [All Posts](https://paragraph.com/@0x9493695d028e374e8e462810b7f1836c3cdfb26e/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0x9493695d028e374e8e462810b7f1836c3cdfb26e): Subscribe to updates