SQLAlchemy备忘录

前言

SQLALchemyPython社区中著名的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 relationshipsqlalchemy.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