SQLAlchemy never makes any assumptions by itself about the table to which a class refers, including that it has no built-in conventions for names, datatypes, or constraints. But this doesn’t mean boilerplate is required; instead, you’re encouraged to create your own automated conventions using helper functions and mixin classes, which is described in detail at Mixin and Custom Base Classes.
>>>Base.metadata.create_all(engine) 2015-10-2917:36:41,372 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 2015-10-2917:36:41,374 INFO sqlalchemy.engine.base.Engine () 2015-10-2917:36:41,375 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 2015-10-2917:36:41,375 INFO sqlalchemy.engine.base.Engine () 2015-10-2917:36:41,377 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users") 2015-10-2917:36:41,378 INFO sqlalchemy.engine.base.Engine () 2015-10-2917:36:41,379 INFO sqlalchemy.engine.base.Engine CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR, fullname VARCHAR, password VARCHAR, PRIMARY KEY (id) )
2015-10-2917:36:41,379 INFO sqlalchemy.engine.base.Engine () 2015-10-2917:36:41,410 INFO sqlalchemy.engine.base.Engine COMMIT
Minimal Table Descriptions vs. Full Descriptions 熟悉CREATE_TABLE的可以看出来VARCHAR这里是没有长度的,对于数据库SQLite和Postgresql,这是允许的,但是其他的一些数据库,这个不可以的。所以如果要正确执行需要指定String的长度:
>>> session.query(User).filter(User.name.in_(['dongcong', 'fake'])).all() 2015-11-02 11:11:37,085 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ? 2015-11-0211:11:37,085 INFO sqlalchemy.engine.base.Engine ('dongcong', 1) 2015-11-02 11:11:37,087 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (?, ?, ?) 2015-11-0211:11:37,088 INFO sqlalchemy.engine.base.Engine ('fake', 'TestUser', 'Nopassword') 2015-11-0211:11:37,091 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.name IN (?, ?) 2015-11-0211:11:37,092 INFO sqlalchemy.engine.base.Engine ('dongcong', 'fake') [<User(name='dongcong', fullname='cheneydc', password='123456')>, <User(name='fake', fullname='TestUser', password='Nopassword')>]
目前,事务还没有结束,执行回滚操作:
1 2 3 4 5
>>> session.rollback() >>> user_1.name >>> dc >>> fake_user in session False
7 查询
查询对象是通过Session中的query()方法创建的。采用的是可变数量的参数,任意数目的类实体或者基于列的实体均可以作为query()方法的参数can be any combination of classes and class-instrumented descriptors。下面加载User实例进行查询:
1 2 3 4 5 6 7 8 9 10 11
>>> for instance in session.query(User).order_by(User.id): ... print instance.name, instance.fullname ... 2015-11-0213:20:31,632 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users ORDER BY users.id 2015-11-0213:20:31,633 INFO sqlalchemy.engine.base.Engine () aaa cheneydc ccc cheney ed eeeddd zxwer zxcvasdf fake TestUser
>>> for name,fullname in session.query(User.name, User.fullname).all(): ... print name, fullname ... 2015-11-0215:16:20,691 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name, users.fullname AS users_fullname FROM users 2015-11-0215:16:20,691 INFO sqlalchemy.engine.base.Engine () aaa cheneydc ccc cheney ed eeeddd zxwer zxcvasdf fake TestUser
>>> for row in session.query(User, User.name).all(): ... print row ... 2015-11-0215:35:17,303 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users 2015-11-0215:35:17,303 INFO sqlalchemy.engine.base.Engine () (<User(name='aaa', fullname='cheneydc', password='123456')>, u'aaa') (<User(name='ccc', fullname='cheney', password='no')>, u'ccc') (<User(name='ed', fullname='eeeddd', password='qweasd')>, u'ed') (<User(name='zxwer', fullname='zxcvasdf', password='098765')>, u'zxwer') (<User(name='fake', fullname='TestUser', password='Nopassword')>, u'fake')
也可以通过label()方法来改变列表达式的名称:
1 2 3 4 5 6 7 8 9 10 11
>>> for row in session.query(User.name.label('name_label')).all(): ... print row.name_label ... 2015-11-0215:37:48,805 INFO sqlalchemy.engine.base.Engine SELECT users.name AS name_label FROM users 2015-11-0215:37:48,806 INFO sqlalchemy.engine.base.Engine () aaa ccc ed zxwer fake
可以发现每次查询都会用到实体类的名称User,可以用aliased()给它一个别名:
1 2 3 4 5 6 7 8 9 10 11
>>> for row in session.query(user_alias, user_alias.name).all(): ... print row ... 2015-11-0215:42:58,489 INFO sqlalchemy.engine.base.Engine SELECT user_alias.id AS user_alias_id, user_alias.name AS user_alias_name, user_alias.fullname AS user_alias_fullname, user_alias.password AS user_alias_password FROM users AS user_alias 2015-11-0215:42:58,489 INFO sqlalchemy.engine.base.Engine () (<User(name='aaa', fullname='cheneydc', password='123456')>, u'aaa') (<User(name='ccc', fullname='cheney', password='no')>, u'ccc') (<User(name='ed', fullname='eeeddd', password='qweasd')>, u'ed') (<User(name='zxwer', fullname='zxcvasdf', password='098765')>, u'zxwer') (<User(name='fake', fullname='TestUser', password='Nopassword')>, u'fake')
>>> for row in session.query(User).order_by(User.id): ... print row ... 2015-11-0215:53:40,182 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users ORDER BY users.id 2015-11-0215:53:40,182 INFO sqlalchemy.engine.base.Engine () <User(name='aaa', fullname='cheneydc', password='123456')> <User(name='ccc', fullname='cheney', password='no')> <User(name='ed', fullname='eeeddd', password='qweasd')> <User(name='zxwer', fullname='zxcvasdf', password='098765')> <User(name='fake', fullname='TestUser', password='Nopassword')>
>>> for row in session.query(User).order_by(User.id)[1:3]: ... print row ... 2015-11-0215:54:01,541 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users ORDER BY users.id LIMIT ? OFFSET ? 2015-11-0215:54:01,542 INFO sqlalchemy.engine.base.Engine (2, 1) <User(name='ccc', fullname='cheney', password='no')> <User(name='ed', fullname='eeeddd', password='qweasd')>
筛选的功能通过filter_by()实现,使用关键词参数:
1 2 3 4 5 6 7 8
>>> for row in session.query(User).filter_by(fullname='cheney'): ... print row ... 2015-11-0216:09:13,818 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.fullname = ? 2015-11-0216:09:13,818 INFO sqlalchemy.engine.base.Engine ('cheney',) <User(name='ccc', fullname='cheney', password='no')>
>>> for row in session.query(User).filter(User.fullname=='cheney'): ... print row ... 2015-11-0216:18:39,058 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.fullname = ? 2015-11-0216:18:39,059 INFO sqlalchemy.engine.base.Engine ('cheney',) <User(name='ccc', fullname='cheney', password='no')>
>>> for row in session.query(User).filter(User.fullname=='cheney').filter(User.name=='ccc'): ... print row ... 2015-11-0216:24:51,982 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.fullname = ? AND users.name = ? 2015-11-0216:24:51,984 INFO sqlalchemy.engine.base.Engine ('cheney', 'ccc') <User(name='ccc', fullname='cheney', password='no')>
常用筛选操作
列举一些filter()常用的过滤操作:
equals:
1
query.filter(User.name == 'ccc')
not equals:
1
query.filter(User.name != 'ccc')
LIKE:
1 2 3 4 5 6 7 8 9
>>> for row in session.query(User).filter(User.fullname.like('%ene%')): ... print row ... 2015-11-0216:29:13,320 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.fullname LIKE ? 2015-11-0216:29:13,321 INFO sqlalchemy.engine.base.Engine ('%ene%',) <User(name='aaa', fullname='cheneydc', password='123456')> <User(name='ccc', fullname='cheney', password='no')>
#example. >>> for row in session.query(User).filter(~User.fullname.in_(['cheneydc', 'cheney'])): ... print row ... 2015-11-0216:33:49,204 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.fullname NOT IN (?, ?) 2015-11-0216:33:49,205 INFO sqlalchemy.engine.base.Engine ('cheneydc', 'cheney') <User(name='ed', fullname='eeeddd', password='qweasd')> <User(name='zxwer', fullname='zxcvasdf', password='098765')> <User(name='fake', fullname='TestUser', password='Nopassword')>
IS NULL:
1 2 3 4
query.filter(User.name == None)
# alternatively, if pep8/linters are a concern query.filter(User.name.is_(None))
IS NOT NULL:
1 2 3 4
query.filter(User.name != None)
# alternatively, if pep8/linters are a concern query.filter(User.name.isnot(None))
>>> query = session.query(User).filter(~User.name.in_(['a', 'b'])) >>> query.all() 2015-11-0217:38:55,658 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.name NOT IN (?, ?) 2015-11-0217:38:55,659 INFO sqlalchemy.engine.base.Engine ('a', 'b') [<User(name='aaa', fullname='cheneydc', password='123456')>, <User(name='ccc', fullname='cheney', password='no')>, <User(name='ed', fullname='eeeddd', password='qweasd')>, <User(name='zxwer', fullname='zxcvasdf', password='098765')>, <User(name='fake', fullname='TestUser', password='Nopassword')>]
first()将第一个结果作为标量返回:
1 2 3 4 5 6 7
>>> query.first() 2015-11-0217:40:29,597 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.password AS users_password FROM users WHERE users.name NOT IN (?, ?) LIMIT ? OFFSET ? 2015-11-0217:40:29,597 INFO sqlalchemy.engine.base.Engine ('a', 'b', 1, 0) <User(name='aaa', fullname='cheneydc', password='123456')>