http://www.kardel.xyz/blog/sqlalchemypython%E6%9C%80%E5%B8%B8%E7%94%A8orm-%E4%BA%8C/
上文介绍了创建engine,创建映射关系,create/drop表,本文,我们来聊下最常用的DML的实现
在此之前,我们说过,我们一般并不会直接使用Engine,如engine.execute()去执行sql,更多的,我们通过session实现
ORM对数据库的入口即是Session,当我们构建应用时,和create_engine的同一级别下,我们定义一个Session类来作为生成新的Session的Factory类
Session的创建
先看代码:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
connect_args = {'check_same_thread': False}
engine = create_engine(engine, echo=False, connect_args=connect_args)
session = sessionmaker(bind=engine)()
分析以上代码
前半部分我们之前已经说过的engine的创建
最后一行,sessionmaker(bind=engine)返回一个Session的Factory类,即也可以写成这样:
Session = sessionmaker(bind=engine)
session = Session()
这样,我们得到一个session对象,现在,我们可以实现对表的操作了
add
我们要在users表中插入一条数据,类比的,相当于,我们需要将User对象存入数据库,session提供add方法
user = User(name='ed', password='edspassword')
session.add(user)
执行完以上操作,我们将user存入session,但并未提交,也就是说,数据并未落盘存入数据库。
Session将会在需要的时候执行相应的SQL命令,这个过程我们称之为flush。如果我们试图查询Ed Jones,所有处于pending状态的信息将会首先被flush,然后负责进行查询的SQL语言在此之后立即被执行。
例如,我们创建一个查询来获取刚刚我们创建的用户(涉及查询的部分我们后续会详细介绍)。这个查询会返回一个和我们之前添加的用户相同的用户实例。事实上这里的Session判断出来了需要返回的行和已经存在内存中的一个映射实例应当是同一个,所以我们会得到一个和之前完全相同的实例
这里ORM所表现的理念,我们称之为identity map。这个设计理念保证了在一个Session对于一个制定行的操作,作用于同一个内存实例上。当一个拥有特定主键的对象出现在Session中时,所有的查询操作对这个主键都会返回一个相同的Python对象。并且,如果你试图引入重复了主键的新的对象时,系统会产生一个错误来阻止你的操作。
如果我们希望改变Ed的密码,可以直接修改之:
user.password = 'xxxxxx'
最后,我们使用commit将以上的处理flush到数据库
session.commit()
另外,我们也可以使用add_all()来批量插入
session.add_all([
User(name='a', password='foobar'),
User(name='b', password='xxg527'),
User(name='c', password='blah')])
query
Session的query函数会返回一个Query对象。query函数可以接受多种参数类型。可以是类,或者是类的instrumented descriptor。然后我们可以通过filter函数在query进行筛选。
下面的这些操作符可以应用在filter函数中
equals:
query.filter(User.name == 'ed')
not equals:
query.filter(User.name != 'ed')
LIKE:
query.filter(User.name.like('%ed%'))
IN:
query.filter(User.name.in_(['ed', 'jack']))
# works with query objects too:
query.filter(User.name.in_(
session.query(User.name).filter(User.name.like('%ed%'))
))
NOT IN:
query.filter(~User.name.in_(['ed', 'jack']))
IS NULL:
query.filter(User.name == None)
# alternatively, if pep8/linters are a concern
query.filter(User.name.is_(None))
IS NOT NULL:
query.filter(User.name != None)
# alternatively, if pep8/linters are a concern
query.filter(User.name.isnot(None))
AND:
# or send multiple expressions to .filter()
query.filter(User.name == 'ed', User.passwd == 'aaas')
OR:
from sqlalchemy import or_
query.filter(or_(User.name == 'ed', User.password == 'asdf'))
MATCH:
query.filter(User.name.match('wendy'))
同时,我们也可以在filter中使用嵌入式的sql
比如:
from sqlalchemy import text
for user in session.query(User).\
filter(text("id<224")).\
order_by(text("id")).all():
最后,query返回的是generative的对象,我们还可以通过一些函数还得到我们需要的直观结果:
all(): 返回列表
first(): 返回第一个元素
one(): 只返回一个元素,当有多个结果,异常
limit(): 返回计数,等于select count(*)
delete & update
有了query对象,我们可以基于此,进行删除或更新操作
query.delete()
query.update(update_dict, synchronize_session='fetch')
参考: