多表关系 - 多对多
简介
多对多是数据库关系中的一种描述,表示多个数据行可以与多个其他数据行相关联。在关系型数据库中,多对多关系通常需要中间表来实现。
多对多关系的一个常见例子是学生和老师之间的关系。一个学生可以有多位老师,而一位老师也可以教多名学生。这种关系可以用多对多关系来描述,其中中间表(通常称为关联表或交叉表)用于跟踪学生和老师之间的关联。
多对多使用场景
在数据库中,多对多关系通常需要三个表:两个主要表和一个中间表。中间表包含两个主要表的外键,用于建立它们之间的关联。这种关系允许灵活地管理数据,同时保持数据的一致性。
总之,多对多关系适用于许多不同的情况,其中多个数据行需要与多个其他数据行相关联,同时保持数据的一致性和灵活性。
定义使用多对多关系
建立多对多关系
关系数据库系统通常不允许在两个表之间实施直接的多对多关系。为避免这一问题,可以通过使用称为联接表的第三个表,将多对多关系拆分为两个一对多关系。
联接表中的每个记录都包含一个匹配字段,该字段包含其联接的两个表的主键值。(在联接表中,这些匹配字段是外键。)当从联接表联接的任何一个表创建联接表的记录时,会为这些外键字段填充数据。
以下是定义多对多关系的步骤。
- 定义三张表。
- 需要创建一个中间表(关系表)。
- 使用
relationship()
方法关联两张表。
# 创建一个中间表
teacher_student_rel = Table(
# 中间表的名字,最好能体现哪两张表
"teacher_student",
Base.metadata,
Column("id", Integer, primary_key=True),
# 其中一张表的描述,作为一个外键,指向 teacher 表的id
Column("teacher_id", Integer, ForeignKey("teacher.id")),
# 其中一张表的描述,作为一个外键,指向 student 表的id
Column("student_id", Integer, ForeignKey("student.id"))
)
# 创建老师的映射
class Teacher(Base):
__tablename__ = "teacher"
id = Column(Integer, primary_key=True)
# name 老师的姓名
# nullable=False 不为空,unique=True 唯一约束,不允许重复
name = Column(String(100), nullable=False, unique=True)
# 参数一:指向另一张表,另外一张表的类名
# 参数二:secondary ,指向中间表的变量名
# 参数三:反向指向,backref 当前表的别名
students = relationship(
"Student",
secondary=teacher_student_rel,
backref="teachers"
)
def __repr__(self):
return f"<Teacher id={self.id} teacher_name={self.name}>"
# 创建学生的映射
class Student(Base):
__tablename__ = "student"
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False, unique=True)
def __repr__(self):
return f"<Student id='{self.id}' name='{self.name}'>"
relationship()
解析
relationship()
方法可以建立两表之间的映射关系,方便访问。
参数一:关联另一张表,另外一张表的类名。
参数二:secondary
指向中间表的变量名。
- 参数三:
backref
反向引用。
创建表
首先,需要创建数据库连接,然后在数据库中创建表。
# 创建数据库连接
engine = create_engine('sqlite:///school.db')
DBSession = sessionmaker(bind=engine)
db_session: Session = DBSession()
if __name__ == '__main__':
# 创建表
Base.metadata.create_all(engine)
# 删除表
# Base.metadata.drop_all(engine)
添加数据
- 创建学生数据。
- 创建老师数据。
- 创建关联数据。
# 添加三个学生,三个老师
stu1 = Student(name="学生1")
stu2 = Student(name="学生2")
stu3 = Student(name="学生3")
tea1 = Teacher(name="老师1")
tea2 = Teacher(name="老师2")
tea3 = Teacher(name="老师3")
db_session.add_all([stu1, stu2, stu3, tea1, tea2, tea3])
# 建立关联关系
# 老师1 --关联-- 学生1,学生2
# 老师2 --关联-- 学生2,学生3
tea1.students = [stu1, stu2]
tea2.students = [stu2, stu3]
# 提交操作
db_session.commit()
# 关闭连接
db_session.close()
查询数据
- 查询学生对应的老师。
- 查询老师对应的学生。
# 查询学生id=1 对应的老师
stu1 = db_session.query(Student).filter_by(id=1).first()
print(stu1.teachers[0].name)
# 查询老师对应的学生
tea1 = db_session.query(Teacher).filter_by(id=1).first()
print(tea1.students[1].name)
更新数据
- 查询学生
id=1
,修改对应的老师姓名。 - 查询老师
id=1
,修改学生的姓名。
# 修改学生 id=1 的老师姓名
stu1 = db_session.query(Student).filter_by(id=1).first()
stu1.teachers[0].name = "老师1修改1"
db_session.commit()
db_session.close()
# 修改老师 id=1 对应的学生姓名
tea1 = db_session.query(Teacher).filter_by(id=1).first()
tea1.students[0].name = "学生1修改1"
# 提交操作
db_session.commit()
# 关闭连接
db_session.close()
删除数据
- 删除学生。
- 删除老师。
- 自动删除关联关系。
# 删除学生
stu1 = db_session.query(Student).filter_by(id=1).first()
db_session.delete(stu1)
# 提交操作
db_session.commit()
# 删除老师
tea1 = db_session.query(Teacher).filter_by(id=1).first()
db_session.delete(tea1)
# 提交操作
db_session.commit()
# 关闭连接
db_session.close()
总结
在本章节中,介绍了多表关系中多对多关系的概念和相关操作。
- 多对多关系简介
- 多对多使用场景
- 建立多对多关系
- 创建表
- 添加数据
- 查询数据
- 更新数据
- 删除数据