在之前代码的基础上添加下面的函数
def remove_album(name):
session = Session()
try:
for a in session.query(Album).filter(Album.name == name).all():
session.delete(a)
session.flush()
session.commit()
finally:
session.close()
Album
类型, 然后调用查询对象的 filter
函数, 指定列 name
的值严格等于该 name
参数. 接下来, 将查询得到的对象逐个删除.来看看搞起来如何
if __name__ == '__main__':
save()
remove_album('stella musica')
list_all()
那么, 接下来试试删
Artist
def remove_artist(name):
session = Session()
try:
for a in session.query(Artist).filter(Artist.name == name).all():
session.delete(a)
session.flush()
session.commit()
finally:
session.close()
if __name__ == '__main__':
save()
remove_artist('katou emiri')
list_all()
崩盘之前的几行输出似乎是这样子的
= Albums =
stella musica
+ Artist: aki misawa
hoshikage no ama no hara
+ Artist: aki misawa
jump!
+ Artist:
remove_artist
确实从数据库中删去了名字为 'katou emiri'
的那个值, 因此名为 'jump!'
的那个 Album
实例的 artist
域成了 None
, 悲剧就发生了.要解决这个问题, 就得在
Album
与 Artist
的关联关系上动动手脚, 加上级联信息.class Artist(Base):
__tablename__ = 'artist'
artist_id = sqla.Column('id', sqla.Integer, primary_key=True)
name = sqla.Column('name', sqla.String)
class Album(Base):
__tablename__ = 'album'
album_id = sqla.Column('id', sqla.Integer, primary_key=True)
name = sqla.Column('name', sqla.String)
artist_id = sqla.Column('artist', sqla.ForeignKey('artist.id'))
# Artist.albums = sqlorm.relationship(Album)
# Album.artist = sqlorm.relationship(Artist)
Album.artist = sqlorm.relationship(
Artist, backref=sqlorm.backref('albums', cascade='all'))
这一次删去了
Artist
向 Album
的 relationship
, 同时为 Album
向 Artist
的 relationship
添加了参数 backref
, 表示反向引用到 Artist
实例的 albums
成员 (上面删去 Artist.albums
这个关联就是为了给 backref
腾个位置出来, 所以 list_all
或者其它任何函数都可以查询得到的 Artist
实例的 albums
成员), 并且在删除 Artist
实例时级联删除对应的 Album
实例集, 而反过来删则不会.最后来尝试修改数据. 下面是一个示例函数
def modify():
session = Session()
try:
artists = session.query(Artist).filter(Artist.name.like('%isa%')).all()
artist = artists[0]
artist.name = 'misawa aki'
artist.albums = filter(lambda a: a.name.startswith('ho'), artist.albums)
artist.albums.append(Album(name='natuhana no kageokuri', artist=artist))
session.flush()
session.commit()
finally:
session.close()
if __name__ == '__main__':
save()
modify()
list_all()
= Artists =
misawa aki
- Album: hoshikage no ama no hara
- Album: natuhana no kageokuri
katou emiri
- Album: jump!
= Albums =
stella musica
+ Artist:
'stella musica'
的 Album
实例确实已经跟名为 misawa aki
(这个实例对象的名字修改也完成了) 的实例脱离关系了, 所以在前一段的输出看不到, 但它实际上还没有从数据库中删去, 因此取得该对象时, 它的 artist
域为 None
.为了确保从反过来, 从集合中删除实例的引用也同步删除表中数据, 需要修改级联方式, 添加
'delete-orphan'
项. 另外, 既然 Artist.albums
这个项目已经移除了, 所以索性把 Album.artist
直接放回 Album
类声明中去好了.class Album(Base):
__tablename__ = 'album'
album_id = sqla.Column('id', sqla.Integer, primary_key=True)
name = sqla.Column('name', sqla.String)
artist_id = sqla.Column('artist', sqla.ForeignKey('artist.id'))
artist = sqlorm.relationship(
Artist, backref=sqlorm.backref('albums',
cascade='all,delete-orphan'))
modify()
就没问题了.PS: 如果需求某个表中建立多个外键, 且它们引用相同的另一张表, 请移步这里.