关系型数据库使用关系把不同表中的行联系起来。上篇随笔中介绍的用户和角色之间是一种简单的关系。即角色到用户的一对多关系,因为一个角色可属于多个用户,而每个用户都只能有一个角色。这种关系在模型中的表示方法如下:
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(64),unique=True) users = db.relationship('User', backref='role') def __repr__(self): return '<Role %r>' % self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(64),unique=True) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) def __repr__(self): return '<User %r>' % self.name
关系使用users 表中的外键连接了两行。添加到User 模型中的role_id 列被定义为外键,就是这个外键建立起了关系。传给db.ForeignKey() 的参数'roles.id' 表明,这列的值是roles 表中行的id 值。
添加到Role 模型中的users 属性代表这个关系的面向对象视角。对于一个Role 类的实例,其users 属性将返回与角色相关联的用户组成的列表。db.relationship() 的第一个参数表明这个关系的另一端是哪个模型。如果模型类尚未定义,可使用字符串形式指定。
db.relationship() 中的backref 参数向User 模型中添加一个role 属性,从而定义反向关系。这一属性可替代role_id 访问Role 模型,此时获取的是模型对象,而不是外键的值。
大多数情况下,db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。例如,如果User 模型中有两个或以上的列定义为Role 模型的外键,SQLAlchemy 就不知道该使用哪列。如果无法决定外键,你就要为db.relationship() 提供额外参数,从而确定所用外键。下表列出了定义关系时常用的配置选项。
backref | 在关系的另一个模型中添加反向引用 |
primaryjoin | 明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定 |
lazy | 指定如何加载相关记录。可选值有select(首次访问时按需加载)、immediate(源对象加载后就加载)、joined(加载记录,但使用联结)、subquery(立即加载,但使用子查询),noload(永不加载)和dynamic(不加载记录,但提供加载记录的查询) |
uselist | 如果设为Fales,不使用列表,而使用标量值 |
secondary | 指定多对多关系中关系表的名字 |
secondaryjoin | SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件 |
除了一对多之外,还有几种其他的关系类型。一对一关系可以用前面介绍的一对多关系表示,但调用db.relationship() 时要把uselist 设为False,把“多”变成“一”。多对一关系也可使用一对多表示,对调两个表即可,或者把外键和db.relationship() 都放在“多”这一侧。由于多对多关系比较复杂,后面会在专门的专题详细介绍。