多对一
一对多关系反过来就是多对一关系,这两种关系模式分别从不同的视角出发。一个作者拥有多篇文章,反过来就是多篇文章属于同一个作者。为了便于区分,我们使用居民和城市来演示多对一关系:多个居民住在同一个城市。多对一关系如下:
在例子中,Citizen类表示居民,City类表示城市。建立多对一关系后,我们将在Citizen类中创建一个标量关系属性city,调用它可以获取单个City对象。
我们在前面介绍过,关系属性在关系模式的出发侧定义。当出发点在“多”这一侧时,我们希望在Citizen类中添加一个关系属性city来获取对应的城市对象,因为这个关系属性返回单个值,我们称之为标量关系属性。在定义关系时,外键总是在“多”这一侧定义,所以在多对一关系中外键和关系属性都定义在“多”这一侧,即City类中:
app.py:建立多对一关系
class Citizen(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(70), unique = True) city_id = db.Column(db.Integer, db.ForeignKey('city.id')) city = db.relationship('City') class City(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(30), unique = True)
这时定义的 city关系属性是一个标量关系(返回单一数据)。当Citizen.city被调用时,SQLAlchemy会根据外键字段city_id存储的值查找对应的City对象并返回,即居民记录对应的城市记录。
>>> from app import Citizen >>> from app import db >>> city1 = City(name = 'DaLian') >>> citizen1 = Citizen(name = 'Xia') >>> citizen1.city= city1 >>> citizen1.city <City (transient 54277680)>
当建立双向关系时,如果不使用backref,那么一对多和多对一关系模式在定义上完全相同,这时可以将一对多和多对一关系模式。我们通常都会为一对多或多对一建立双向关系,这时将弱化这两种关系的区别,一律称为一对多关系。
class Citizen(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(70), unique = True) city_id = db.Column(db.Integer, db.ForeignKey('city.id')) city = db.relationship('City', back_populates='citizen') def __repr__(self): return '<Citizen %r>' % self.name class City(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(30), unique = True) #back_populates的值为另一侧的关系属性名 #relationship函数的第一个参数是另一侧的模型名(类型) citizen = db.relationship('Citizen', back_populates='city') >>> from app import Citizen, City, db >>> city1 = City(name = 'DaLian') >>> citizen1 = Citizen(name = 'xiaxiaoxu') >>> citizen2 = Citizen(name = 'xufengchai') >>> citizen1.city = city1 >>> citizen2.city = city1 >>> city1.citizen [<Citizen 'xiaxiaoxu'>, <Citizen 'xufengchai'>] >>> citizen2.city <City 'DaLian'> >>> citizen1.city <City 'DaLian'>