Python的ORM框架中SQLAlchemy库的查询操作的教程


Posted in Python onApril 25, 2015

1. 返回列表和标量(Scalar)

前面我们注意到Query对象可以返回可迭代的值(iterator value),然后我们可以通过for in来查询。不过Query对象的all()、one()以及first()方法将返回非迭代值(non-iterator value),比如说all()返回的是一个列表:

>>> query = session.query(User).\
>>>     filter(User.name.like('%ed')).order_by(User.id)
>>> query.all() 
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 LIKE ? ORDER BY users.id
('%ed',)
 
[User('ed','Ed Jones', 'f8s7ccs'), User('fred','Fred Flinstone', 'blah')]

first()方法限制并仅作为标量返回结果集的第一条记录:

>>> query.first() 
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 LIKE ? ORDER BY users.id
 LIMIT ? OFFSET ?
('%ed', 1, 0)
 
<User('ed','Ed Jones', 'f8s7ccs')>

one()方法,完整的提取所有的记录行,并且如果没有明确的一条记录行(没有找到这条记录)或者结果中存在多条记录行,将会引发错误异常NoResultFound或者MultipleResultsFound:

>>> from sqlalchemy.orm.exc import MultipleResultsFound
>>> try: 
...   user = query.one()
... except MultipleResultsFound, e:
...   print e
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 LIKE ? ORDER BY users.id
('%ed',)
 
Multiple rows were found for one()

>>> from sqlalchemy.orm.exc import NoResultFound
>>> try: 
...   user = query.filter(User.id == 99).one()
... except NoResultFound, e:
...   print e
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 LIKE ? AND users.id = ? ORDER BY users.id
('%ed', 99)
 
No row was found for one()

2. 使用原义SQL (Literal SQL)

Query对象能够灵活的使用原义SQL查询字符串作为查询参数,比如我们之前用过的filter()和order_by()方法:

>>> for user in session.query(User).\
...       filter("id<224").\
...       order_by("id").all(): 
...   print user.name
SELECT users.id AS users_id,
    users.name AS users_name,
    users.fullname AS users_fullname,
    users.password AS users_password
FROM users
WHERE id<224 ORDER BY id
()
 
ed
wendy
mary
fred

当然很多人可能会和我感觉一样,会有些不适应,因为使用ORM就是为了摆脱SQL语句的,没想到现在又看到SQL的影子了。呵呵,SQLAlchemy也要照顾到使用上的灵活性嘛,毕竟有些查询语句直接编入要容易得多。

当然绑定参数也可以用基于字符串的SQL指派,使用冒号来标记替代参数,然后再使用params()方法指定相应的值:

>>> session.query(User).filter("id<:value and name=:name").\
...   params(value=224, name='fred').order_by(User.id).one() 
SELECT users.id AS users_id,
    users.name AS users_name,
    users.fullname AS users_fullname,
    users.password AS users_password
FROM users
WHERE id<User('fred','Fred Flinstone', 'blah')>

到这里,SQL语句的样子已经初见端倪了,其实我们可以更极端一点,直接使用SQL语句,什么?这样就失去ORM的价值了!别急,这里只是介绍一下支持这种用法,当然我建议不到万不得已,尽量不要这样写,因为可能会有兼容的问题,毕竟各个数据库的SQL方言不一样。不过有一点需要注意的是,如果要直接使用原生SQL语句,在被query()所查询的映射类中,你必须保证语句所指代的列仍然被映射类所管理,比如接下来的例子:

>>> session.query(User).from_statement(
...           "SELECT * FROM users where name=:name").\
...           params(name='ed').all()
SELECT * FROM users where name=?
('ed',)
 
[<User('ed','Ed Jones', 'f8s7ccs')>]

我们还可以在query()中直接使用列名来指派我们想要的列而摆脱映射类的束缚:

>>> session.query("id", "name", "thenumber12").\
...     from_statement("SELECT id, name, 12 as "
...         "thenumber12 FROM users where name=:name").\
...         params(name='ed').all()
SELECT id, name, 12 as thenumber12 FROM users where name=?
('ed',)
 
[(1, u'ed', 12)]

3. 计数 (Counting)

对于Query来说,计数功能也有个单独的方法称为count():

>>> session.query(User).filter(User.name.like('%ed')).count() 
SELECT count(*) AS count_1
FROM (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 LIKE ?) AS anon_1
('%ed',)
 
2

count()方法被用于确定返回的结果集中有多少行,让我们观察一下产生的SQL语句,SQLAlchemy先是取出符合条件的所有行集合,然后再通过SELECT count(*)来统计有多少行。当然有点SQL知识的同学可能知道这条语句可以以更精简的方式写出来,比如SELECT count(*) FROM table,当然现代版本的SQLAlchemy不会去揣摩这样的想法。

假使我们要让查询语句更加精炼或者要明确要统计的列,我们可以通过表达式func.count()直接使用count函数,比如下面的例子介绍统计并返回每个唯一的用户名字:

>>> from sqlalchemy import func
>>> session.query(func.count(User.name), User.name).group_by(User.name).all() 
SELECT count(users.name) AS count_1, users.name AS users_name
FROM users GROUP BY users.name
()
 
[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]

对于刚才提到的简单SELECT count(*) FROM table语句,我们可以通过下面的例子来实现:

>>> session.query(func.count('*')).select_from(User).scalar()
SELECT count(?) AS count_1
FROM users
('*',)
 
4

当然如果我们直接统计User的主键,上面的语句可以更加简练,我们可以省去select_from()方法:

>>> session.query(func.count(User.id)).scalar() 
SELECT count(users.id) AS count_1
FROM users
()
 
4
Python 相关文章推荐
python网络爬虫采集联想词示例
Feb 11 Python
python实现文件快照加密保护的方法
Jun 30 Python
python 执行shell命令并将结果保存的实例
May 11 Python
Python使用matplotlib和pandas实现的画图操作【经典示例】
Jun 13 Python
python得到qq句柄,并显示在前台的方法
Oct 14 Python
在pycharm 中添加运行参数的操作方法
Jan 19 Python
matplotlib实现区域颜色填充
Mar 18 Python
使用PyOpenGL绘制三维坐标系实例
Dec 24 Python
爬虫代理的cookie如何生成运行
Sep 22 Python
使用AJAX和Django获取数据的方法实例
Oct 25 Python
关于python scrapy中添加cookie踩坑记录
Nov 17 Python
Django操作cookie的实现
May 26 Python
Python实现单词拼写检查
Apr 25 #Python
在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程
Apr 25 #Python
使用PDB简单调试Python程序简明指南
Apr 25 #Python
Python脚本判断 Linux 是否运行在虚拟机上
Apr 25 #Python
在Python中使用cookielib和urllib2配合PyQuery抓取网页信息
Apr 25 #Python
使用Python的Tornado框架实现一个一对一聊天的程序
Apr 25 #Python
使用Python发送邮件附件以定时备份MySQL的教程
Apr 25 #Python
You might like
memcached 和 mysql 主从环境下php开发代码详解
2010/05/16 PHP
PHP一个简单的无需刷新爬虫
2019/01/05 PHP
在页面上点击任一链接时触发一个事件的代码
2007/04/07 Javascript
用户注册常用javascript代码
2009/08/29 Javascript
CSS和JS标签style属性对照表(方便js开发的朋友)
2010/11/11 Javascript
js/jQuery对象互转(快速操作dom元素)
2013/02/04 Javascript
javascript标签在页面中的位置探讨
2013/04/11 Javascript
jquery代码规范让代码越来越好看
2017/02/03 Javascript
Vue2.0表单校验组件vee-validate的使用详解
2017/05/02 Javascript
微信小程序框架wepy之动态控制类名
2018/09/14 Javascript
vue使用高德地图点击下钻上浮效果的实现思路
2019/10/12 Javascript
浅谈vuex为什么不建议在action中修改state
2020/02/02 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
[04:11]2014DOTA2国际邀请赛 CIS遗憾出局梦想不灭
2014/07/09 DOTA
[02:41]2015国际邀请赛中国区预选赛观战指南
2015/05/20 DOTA
[03:59]第二届DOTA2亚洲邀请赛选手传记-VGJ.rOtk
2017/04/03 DOTA
Python的Django框架使用入门指引
2015/04/15 Python
python对指定目录下文件进行批量重命名的方法
2015/04/18 Python
python使用openpyxl库修改excel表格数据方法
2018/05/03 Python
python pands实现execl转csv 并修改csv指定列的方法
2018/12/12 Python
ERLANG和PYTHON互通实现过程详解
2019/07/05 Python
Python中typing模块与类型注解的使用方法
2019/08/05 Python
python实现简易淘宝购物
2019/11/22 Python
Python中内建模块collections如何使用
2020/05/27 Python
东方通信股份有限公司VC面试题
2014/08/27 面试题
汉语言文学毕业生求职信
2013/10/01 职场文书
一月红领巾广播稿
2014/02/11 职场文书
物流毕业生个人的自我评价
2014/02/13 职场文书
活动总结模板
2014/05/09 职场文书
2014年向国旗敬礼活动方案
2014/09/27 职场文书
办公室主任个人对照检查材料思想汇报
2014/10/11 职场文书
三年级上册科学教学计划
2015/01/21 职场文书
八年级语文教学反思
2016/03/03 职场文书
2016年社区创先争优活动总结
2016/04/05 职场文书
MySQL解决Navicat设置默认字符串时的报错问题
2022/06/16 MySQL
二维码条形码生成的JavaScript脚本库
2022/07/07 Javascript