本文中的例子都是基于 Python 2.7, SQLAlchemy 0.7 的. 数据库使用 SQLite.
废话少说, 先来一段代码
import sqlalchemy as sqla
import sqlalchemy.orm as sqlorm
from sqlalchemy.ext.declarative import declarative_base as sqla_declarative_base
Base = sqla_declarative_base()
engine = sqla.create_engine('sqlite:///test.db', echo=True)
class Artist(Base):
__tablename__ = 'artist'
artist_id = sqla.Column('id', sqla.Integer, primary_key=True)
name = sqla.Column('name', sqla.String)
Base.metadata.bind = engine
Base.metadata.create_all()
Session = sqlorm.scoped_session(sqlorm.sessionmaker(bind=engine))
def save_artist():
artist = Artist(name='aki misawa')
session = Session()
try:
session.add(artist)
session.flush()
print 'Artist id:', artist.artist_id
session.commit()
finally:
session.close()
if __name__ == '__main__':
save_artist()
artist
的 artist_id
在这一行
Base = sqla_declarative_base()
create_engine
调用则绑定数据库以及文件, 并设置回显 SQL.然后重头来了, 声明类型
Artist
class Artist(Base):
__tablename__ = 'artist'
artist_id = sqla.Column('id', sqla.Integer, primary_key=True)
name = sqla.Column('name', sqla.String)
__tablename__
表示表名, 接着以整数类型声明主键, 以及另一列 name
为字符串类型. 不用 varchar
真心舒畅.接着两句
Base.metadata.bind = engine
Base.metadata.create_all()
虽然没看 SQLAlchemy 的实现, 但是构建
Base
类, 以及调用 create_all
建表有点多此一举的感觉. 我还是比较喜欢 GAE 存储那种直白的风格.后面的
Session = sqlorm.scoped_session(sqlorm.sessionmaker(bind=engine))
def save_artist():
artist = Artist(name='aki misawa')
session = Session()
try:
session.add(artist) # a
session.flush()
print 'Artist id:', artist.artist_id
session.commit()
finally:
session.close()
add
而是 save
函数, SQLAlchemy 0.7 版本好像这里修改了, 而且 save
还不能用了, 这种不向前兼容还真是秉承 Python 的大胆.而在将
artist
对象存入数据库之前, 成员 artist_id
是没有手动赋值的, 保存之后, session
会自动为之关联一个数据库中的主键值. 不过这个主键值在会话关闭后就失效了. 也就是说, 如果把上面的函数改成下面这个样子def save_artist():
artist = Artist(name='aki misawa')
session = Session()
try:
session.add(artist)
session.flush()
# print 'Artist id:', artist.artist_id
session.commit()
finally:
session.close()
print 'Artist id:', artist.artist_id
接下来一个尝试便是外键. 现在增加一个类型
Album
, 包含一个 Artist
作为外键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'))
ForeignKey
就是个整数 (sqlalchemy.Integer
), 因此保存代码不能这样写def save():
artist = Artist(name='aki misawa')
album = Album(name='stella musica', artist_id=artist)
session = Session()
try:
session.add(artist)
session.add(album)
session.flush()
session.commit()
finally:
session.close()
album.artist
不是个合适的类型没法丢进数据表. 因此只能很残念地改成 artist=artist.artist_id
.但是根据刚才所述,
artist_id
这个成员要等到 artist
被丢进数据库才行, 那只好这样来了def save():
artist = Artist(name='aki misawa')
session = Session()
try:
session.add(artist)
session.flush() # 0
album = Album(name='stella musica', artist_id=artist.artist_id)
session.add(album)
session.flush() # 1
session.commit()
finally:
session.close()
flush
真心看着很想吐槽啊, 要如何来改进这一点呢? 敬请关注下节: 外键与关系.