SQLAlchemy备忘录
前言
SQLALchemy
是Python
社区中著名的ORM
库,由于本职工作是前端,Python
相关技术栈不常用到,经常性的会造成遗忘,所以记下这篇文章,已备忘速查
以下代码演示环境为:
- 数据库:
MySQL5.7
- 操作系统:
Windows10
- 开发工具:
PyCharm2019.3.2
Python3.8
安装
1 | # 安装sqlalchemy |
引入对应的模块
1 | from sqlalchemy.orm import sessionmaker, relationship |
连接数据库并创建session
1 | # 创建连接 |
创建表的class定义
1 | Base = declarative_base() |
创建表(如果表已经存在,不会重新创建覆盖)
1 | Base.metadata.create_all(engine) |
删除表
1 | Base.metadata.drop_all(engine) |
基本CRUD
1 | def get_vod(vid): |
创建多对多关系
创建多对多关系,需要通过中间表实现1
2
3
4
5
6
7
8
9class 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
,则需要这样操作1
2
3
4
5
6
7def 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
, 则操作就会变得非常简单1
2
3
4
5
6
7
8
9
10
11class 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
的值1
2
3
4
5
6
7
8
9
10
11
12
13
14class 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
创建一对多关系
创建一对多关系,只需要在子表中设置外键, 外键的值为父表的主键值, 不需要额外建立中间表;多对多关系本质上就是通过两张表与中间表建立一对多关系实现的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class 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
不是一个列表1
2
3
4class Vod(Base):
# ...
# 默认uselist=True, 通过play_bilibili获取到的值是一个列表
play_bilibili = relationship('Play', uselist=False, backref='vod');