SQLAlchemy ORM 参考

#Session

###建立 from sqlalchemy import create_engine from sqlalchemy.orm import sessionmakerhtml

engine = create_engine('sqlite:///:memory:', echo=False)
Session = sessionmaker(bind=engine)
session = Session()

echo 负责设定是否输出生成的 SQL 语句。mysql

create_engine 返回的是一个 Engine 对象,它负责对接 DBAPI。Session 对象会更多被直接使用。sql

session 某种意义上相似于一个缓存,他有 commit, rollback, close 等方法。也所以 session 实例的生命周期维护应该位于使用它们的函数以外,与具体的应用逻辑区分开,以免数据污染和保证 rollback/close 的调用。如:-- 参考数据库

from contextlib import contextmanager

@contextmanager
def session_scope():
	"""Provide a transactional scope around a series of operations."""
	session = Session()
	try:
    	yield session
    	session.commit()
	except:
    	session.rollback()
    	raise
	finally:
    	session.close()


def run_my_program():
	with session_scope() as session:
    	ThingOne().go(session)
    	ThingTwo().go(session)

###同步 值得注意的是,在同一个 session 内,不一样 Instance 是共享一份数据缓存的,即:缓存

>>> s = Session()
>>> foo = s.query(Item).get(9)
>>> bar = s.query(Item).get(9)
>>> foo.amount
1
>>> foo.amount += 1
>>> bar.amount
2

既然 session 起的是一个缓存的做用,就意味着他的数据与数据库之间并不能保持多高的一致性。session

当咱们须要刷新数据时,可使用 refesh() 方法:分布式

>>> foo.amount
1
>>> s.refresh(foo)
>>> s.commit()
>>> foo.amount
0

注意记得提交。commit() 方法是向数据库提交请求的最后一步确认,在它被调用以前,数据都不会获得更新。包括全部被 flush() 的请求,虽然他们已经被传入数据库了。ide

commit() 以前,这些请求都还能够经过 rollback() 取消掉。函数

###自增(减)原子操做 对某些数据一致性要求较高的字段,在不考虑分布式存储的前提下,一种有效的手段是使用嵌入的 SQL 子句来赋值。code

mysql> update item set amount=amount-1 where id=9;

这能够有效避免由于多 session 同时操做同一对象时,使用字面量赋值可能引起的一致性风险。

这种操做的 orm 版语法是:

foo.amount = foo.__table__.c.amount - 1

这里引用了 foo.__table__ 属性,它是 orm 映射中的 Table 对象,上面的语句在提交时就会生成一个嵌入的 SQL 子句来进行赋值。

#MAP

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):
	__tablename__ = 'user'

	id = Column(Integer, primary_key=True)
	name = Column(String)

从 Python 类到 sql 表,须要一套映射逻辑,sqlalchemy 提供了一套默认的解决方案,就是 declarative_base

这里单独的一行 Base=declarative_base() 表示了你能够有不少种方式自定义基类,好比继承 Base,或者给 declarative_base(**kwargs) 传参。-- 参考

至于 User 类,因为 sqlalchemy 默认不会去作任何推导,你须要显示指定 __tablename__ 参数和至少一个主键。

Integer 类型没有指定长度,是由于这种修饰参数仅在建表时有用。

#Query

new

tim = User(name='tim')
session.add(tim)
session.flush()

sqlalchemy 对待请求的处理方式是惰性的,他只在必要的时候才访问数据库。必要的一种定义是 query:

session.query(User).filter_by(name='tim')

当即同步到数据库的方式是使用 .flush() 方法。

另一个很是有趣的特性是,sqlalchemy 可以在同一个 session 中分别出表记录的惟一性。即:

>>> tim is session.query(User).filter_by(name='tim')
>>> True

对于同一条数据库记录,不论是你新建的,仍是屡次从库中取出的,他们的 Python id 都是同样的。这种区分就是前面提到的 映射声明必须提供主键 所带来的一个好处。

query 对象

query() 的参数能够不少变,能够是一个 Model 类,或他的某些属性的组合:

foo = session.query(User, User.id).filter(User.name=='tim').first()

这种 query 方式返回的元组对象都是关键字命名的,并且支持属性式访问,如:

>>> foo.User.id == foo.id
>>> True

若是想起别名,可使用 .label() 方法:

>>> foo = session.query(User.id.label('user_id')).filter_by(name='tim')
>>> foo.user_id
>>> 1

对于 LIMIT 和 OFFSET 参数,能够直接对 Query 对象使用 Python 切片操做。

session.query(User)[20:10]

最后,Query 对象是可迭代的。尽管上面的例子为了偷懒没有使用过迭代方法,但它是支持的!

###filter filter() 较于 filter_by() 是一种更通用的方法,支持全部的 sql 表达式。filter() 返回的仍然是一个 Query 对象,因此你能够连续调用 filter() 方法,或者图省事把复合查询语句放进同一个 filter() 里

session.query(User).filter(id>1, name=='tim')

session.query(User).filter(id>1).filter(name=='tim')

一些经常使用的表达式语句:

  • User.name == 'tim'
  • User.name != 'tim'
  • User.name.like('tim')
  • User.name.in_(['tim', 'White'])
  • ~User.name.in_(['tim', 'white'])
  • User.name == None or User.name.is_(None)
  • User.name != None or User.name.isnot(None)
  • from sqlalchemy import or_ /// filter(or_(expr1, expr2))
  • User.name.match('tim')

###order_by session.query(User).order_by(User.id.desc())

or

from sqlalchemy import desc, asc

session.query(User).order_by(asc(User.id))

all(), one(), first()

Query 对象虽然是可迭代的,但对于多数肯定需求的情况,咱们可能更但愿直接把须要的数据取出来。

all()first() 顾名思义,特别的是 one()

它较于 first() 多了一条约束,即Query 对象的结果集必须只包含一个对象,不然报错,即:

session.query(User).filter(name=='tim').one()

等价于:

foo = session.quert(User).filter(name='tim')
assert len(foo.all()) == 1
return foo.first()

###SQL 在如 filter()order_by() 这样的方法中,条件表达式还能够是原始的 sql 语句,只须要用 text() 把语句包起来:

from sqlalchemy import text

users = session.query(User).filter(text('id<10')).order_by(text('id'))

另外一种更完全的 sql 执行方式是使用 from_statement() 方法:

session.query(User).from_statement(text('SELECT * FROM user where id<10 and status=1')).all()

此时还能够直接 Query 列名:

>>> session.query('id', 'name', 'status').from_statement('SELECT * from user where class=3').all()
>>> [(1, 'jack', 0), (2, 'rose', 1)]

###counting 一种简单的计数是对 Query 对象使用 count() 方法,用于返回 Query 对象的行数。

另外一种较复杂的是 func.count(),它支持细分计数:

from sqlalchemy import func

session.query(func.count(User.class), User.class).filter_by(User.class='a')

session.query(func.count(User.class), User.class).group_by(User.class).all()

###关系 略

相关文章
相关标签/搜索