社交WEB应用允许用户之间相互联系,在本章我们将学到如何在Flasky中实现关注功能,让用户“关注”其它用户,并在首页只显示所关注用户发布的博客文章列表。本节将再论数据库关系,讲解多对多关系以及自引用关系在ORM模型中表示。
关系型数据库使用关系建立起记录之间的联系,其中“一对多”关系是最常用的关系模型,它把一个记录和一组相关的记录联系在一起。实现这种关系时,要在多这一侧加入一个外键,指向“一”这一侧连接的记录。多数其它关系类型都可以从一对多类型中衍生:
- 多对一:从多这一侧看就是“一对多关系”;
- 一对一:简化版的“一对多“关系,限制多这一侧最多只能有一个记录即可;
唯一不能从“一对多”衍生出来的关系是“多对多”关系,这种关系的两侧都有多个记录,接下来将详细讨论“多对多”关系。
一. 多对多关系:学生和课程
一个典型的多对多关系:学生表和课程表,一个学生可以选多门课程,一门课程也会被多个学生选,因此两侧都需要一组外键。解决办法是添加第三张表,这个表是关联表,将多对多关系分解成原表和关联表之间的两个一对多关系。
这个例子中的关联表是registrations,表中的每一行表示一个学生注册的一门课程。上图的多对多关系可使用如下代码表示:
from sqlalchemy import Integer, String, create_engine, \
Column, Table, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///demo.sqlite', echo=True)
Base = declarative_base(engine)
session = sessionmaker(bind=engine)()
registrations = Table(
'registrations',
Base.metadata,
Column('student_id', Integer, ForeignKey('students.id')),
Column('classes_id', Integer, ForeignKey('classes.id'))
)
class Class(Base):
__tablename__ = "classes"
id = Column(Integer, primary_key=True)
name = Column(String)
class Student(Base):
__tablename__ = "students"
id = Column(Integer, primary_key=True)
name = Column(String)
classes = relationship(
Class, secondary=registrations,
backref=backref('students', lazy='dynamic'),
lazy='dynamic')
Base.metadata.drop_all()
Base.metadata.create_all()
运行结果(运行上述代码,表格将自动创建):
多对多关系仍使用定义一对多关系的relationship()方法定义,但在多对多关系中,必须把secondary参数设为关联表。多对多关系可以在任何一个类中定义,backref参数会处理好关系的另一侧。关联表就是一个简单的表,不是模型,SQLAlchemy会自动接管这个表。
classes关系使用列表语义定义,处理对对多关系时将非常简单:
# 分别