SQLAlchemy是SQL的对象关系映射(ORM, Object-Relational Mapping)的工具. 和传统直接操作SQL相比, 使用SQLAlchemy的对象来操作数据库更为直观.
例如, 传统Python的DB-API返回的数据库表是列表, 内含多个元组, 每个元组代表一行数据. 这种数据结构并不直观, 而使用对象的话会更为直观:
# DB-API 返回的数据库表结构
[
('1', 'Michael'),
('2', 'Bob'),
('3', 'Adam')
]
# 使用类来表达表的结构
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name
[
User('1', 'Michael'),
User('2', 'Bob'),
User('3', 'Adam')
]
安装很简单:
# PIP
pip install sqlalchemy
# Conda
conda install sqlalchemy
使用示例
维基示例: 这里创建一个电影对象和导演对象, 其中, 电影对象使用外键来指定导演表的对象.
创建Python类
- 首先需要创建sqlalchemy的ORM的基类:
declarative_base
- 使用基类进行继承. 要指定表名, 用
__tablename__
- 如果需要外键, 用
relation
或者relationship
(等价) 绑定关系. - 对象初始化后, 如有外键, 也要指定外键(哪边初始化外键都可以)
''' 创建两个Python类以及DBMS中对应的数据表'''
# 导入基础类, create_engine方法
from sqlalchemy import Integer, String, ForeignKey, Column, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, sessionmaker
# 创建对象的基类
Base = declarative_base()
# 定义自定义的类对象
class Movie(Base):
# 表的名字
__tablename__ = 'movies'
# 表的结构
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
year = Column(Integer)
directed_by = Column(Integer, ForeignKey('directors.id'))
# 外键对象, 上面directed_by使用
director = relation("Director", backref='movies', lazy=False)
# 类的初始化和表达
def __init__(self, title=None, year=None):
self.title = title
self.year = year
def __repr__(self):
return "Movie(%r, %r, %r)" % (self.title, self.year, self.director)
# 上述类中使用的ForeignKey, Director类.
class Director(Base):
__tablename__ = 'directors'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False, unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return "Director(%r)" % (self.name)
# 创建Movie类对象, 并将director指向新的Director对象.
m1 = Movie("Star Trek", 2009)
m1.director = Director("JJ Abrams")
# 创建Director对象, 并创建两部电影进行绑定
# 依赖于 relation("Director", backref='movies', lazy=False)
d2 = Director("George Lucas")
d2.movies = [Movie("Star Wars", 1977), Movie("THX 1138", 1971)]
初始化数据库连接
- 使用
create_engine
来初始化数据库连接引擎, 需要指定各种信息. 例如create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
- 返回的引擎, 可以用来创建数据库连接Session, 从而实现对数据库的操作.
- 操作数据库, 例如
add
,query
,commit
,rollback
,close
等. 和Python操作SQL类似.
# 初始化数据库连接
engine = create_engine('dbms://user:pwd@host/dbname')
Base.metadata.create_all(engine)
''' 插入数据, 并使电影和导演对象可以互相引用'''
# 创建DBSession类型和对象.
# 这个Session对象相当于数据库连接.
Session = sessionmaker(bind=engine)
session = Session()
# 数据库更新
try:
session.add(m1)
session.add(d2)
session.commit()
except:
session.rollback()
# 关闭数据库
session.close()
查询数据
# 如果前面的session没关, 可以直接查询, 这里假设关了
session = Session()
# 创建Query查询. 这里是查询所有结果
alldata = session.query(Movie).all()
for somedata in alldata:
print somedata
'''
Movie('Star Trek', 2009L, Director('JJ Abrams'))
Movie('Star Wars', 1977L, Director('George Lucas'))
Movie('THX 1138', 1971L, Director('George Lucas'))
'''
# 以下查询使用filter(相当于where)
# 最后用`one()` 返回唯一行, `all()`返回所有行
movie1 = session.query(Movie).filter(Movie.id=='1').one()
注意, 当设置外键关系是lazy=False
时, 实际发起的SQL是:
SELECT movies.id, movies.title, movies.year, movies.directed_by, directors.id, directors.name
FROM movies LEFT OUTER JOIN directors ON directors.id = movies.directed_by
默认的外键关系是lazy=True
, 此时将首先发起对电影列表的查询, 并在必要时(延迟加载逐一查询导演的名称:
SELECT movies.id, movies.title, movies.year, movies.directed_by
FROM movies
SELECT directors.id, directors.name
FROM directors
WHERE directors.id = %s
实际上, ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。
网友评论