sqlalchemy级联一记

下面详细介绍 SQLAlchemy 里单对单级联、单对多级联和多对多级联的实现,以及对应的 CRUD 操作,同时给出完整的代码示例。

单对单级联

实现思路

单对单关系意味着一个父对象只关联一个子对象,子对象也只关联一个父对象。可以通过设置 relationship 中的 uselist=False 来表示单对单关系,并且使用 cascade 参数实现级联操作。

代码示例

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base

# 创建基类
Base = declarative_base()

# 定义单对单关系的模型
class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    # 单对单关系,设置级联操作
    child = relationship("Child", back_populates="parent", uselist=False, cascade="all, delete-orphan")


class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship("Parent", back_populates="child")


# 创建数据库引擎
engine = create_engine('sqlite:///test.db')
# 创建表
Base.metadata.create_all(engine)
# 创建会话
Session = sessionmaker(bind=engine)
session = Session()

# 创建操作
def create_one_to_one():
    parent = Parent(name='Parent')
    child = Child(name='Child')
    parent.child = child
    session.add(parent)
    session.commit()
    return parent

# 读取操作
def read_one_to_one():
    parent = session.query(Parent).first()
    if parent:
        print(f"Parent: {parent.name}, Child: {parent.child.name if parent.child else 'No child'}")
    return parent

# 更新操作
def update_one_to_one():
    parent = session.query(Parent).first()
    if parent:
        parent.name = 'Updated Parent'
        if parent.child:
            parent.child.name = 'Updated Child'
        session.commit()
    return parent

# 删除操作
def delete_one_to_one():
    parent = session.query(Parent).first()
    if parent:
        session.delete(parent)
        session.commit()


单对多级联

实现思路

单对多关系表示一个父对象可以关联多个子对象,子对象只关联一个父对象。使用 relationship 建立关联,cascade 参数实现级联操作。

代码示例

# 定义单对多关系的模型
class Team(Base):
    __tablename__ = 'team'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    # 单对多关系,设置级联操作
    players = relationship("Player", back_populates="team", cascade="all, delete-orphan")


class Player(Base):
    __tablename__ = 'player'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    team_id = Column(Integer, ForeignKey('team.id'))
    team = relationship("Team", back_populates="players")


# 创建操作
def create_one_to_many():
    team = Team(name='Team A')
    player1 = Player(name='Player 1')
    player2 = Player(name='Player 2')
    team.players.extend([player1, player2])
    session.add(team)
    session.commit()
    return team

# 读取操作
def read_one_to_many():
    team = session.query(Team).first()
    if team:
        print(f"Team: {team.name}, Players: {[player.name for player in team.players]}")
    return team

# 更新操作
def update_one_to_many():
    team = session.query(Team).first()
    if team:
        team.name = 'Updated Team'
        for player in team.players:
            player.name = f"Updated {player.name}"
        session.commit()
    return team

# 删除操作
def delete_one_to_many():
    team = session.query(Team).first()
    if team:
        session.delete(team)
        session.commit()


多对多级联

实现思路

多对多关系需要一个中间表来关联两个实体。通过 relationshipsecondary 参数指定中间表,并使用 cascade 实现级联操作。

代码示例

# 定义中间表
association_table = Table('association', Base.metadata,
                          Column('student_id', Integer, ForeignKey('student.id')),
                          Column('course_id', Integer, ForeignKey('course.id'))
                          )

# 定义多对多关系的模型
class Student(Base):
    __tablename__ = 'student'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    # 多对多关系,设置级联操作
    courses = relationship("Course", secondary=association_table, back_populates="students", cascade="all, delete")


class Course(Base):
    __tablename__ = 'course'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    students = relationship("Student", secondary=association_table, back_populates="courses")


# 创建操作
def create_many_to_many():
    student = Student(name='Student')
    course1 = Course(name='Course 1')
    course2 = Course(name='Course 2')
    student.courses.extend([course1, course2])
    session.add(student)
    session.commit()
    return student

# 读取操作
def read_many_to_many():
    student = session.query(Student).first()
    if student:
        print(f"Student: {student.name}, Courses: {[course.name for course in student.courses]}")
    return student

# 更新操作
def update_many_to_many():
    student = session.query(Student).first()
    if student:
        student.name = 'Updated Student'
        for course in student.courses:
            course.name = f"Updated {course.name}"
        session.commit()
    return student

# 删除操作
def delete_many_to_many():
    student = session.query(Student).first()
    if student:
        session.delete(student)
        session.commit()


测试代码

if __name__ == "__main__":
    # 单对单关系操作
    print("One-to-One Relationship:")
    create_one_to_one()
    read_one_to_one()
    update_one_to_one()
    read_one_to_one()
    delete_one_to_one()

    # 单对多关系操作
    print("\nOne-to-Many Relationship:")
    create_one_to_many()
    read_one_to_many()
    update_one_to_many()
    read_one_to_many()
    delete_one_to_many()

    # 多对多关系操作
    print("\nMany-to-Many Relationship:")
    create_many_to_many()
    read_many_to_many()
    update_many_to_many()
    read_many_to_many()
    delete_many_to_many()

    session.close()


代码解释

  • 单对单关系ParentChild 模型通过 relationship 建立一对一关联,uselist=False 明确为单对单,cascade="all, delete-orphan" 确保父对象删除时子对象也被删除。
  • 单对多关系TeamPlayer 模型建立一对多关联,Team 可关联多个 Player,同样使用 cascade="all, delete-orphan" 实现级联删除。
  • 多对多关系StudentCourse 通过中间表 association_table 建立多对多关联,cascade="all, delete" 保证删除学生时相关课程关联也被删除。

注意事项

  • 上述代码使用 SQLite 数据库,你可以根据需求更换数据库引擎。
  • 每次操作完成后记得提交会话(session.commit())和关闭会话(session.close())。
posted @ 2025-04-10 22:27  夏目&贵志  阅读(24)  评论(0)    收藏  举报