Python:轻量级 ORM 框架 peewee 用法详解

刚参加工作的时候,学会了写存储过程,写得贼麻溜,那段时间写了不少很长的存储过程,把很多逻辑代码都放进去了。简直就是大坑啊。现在总喜欢用 ORM 框架,简单、方便,尤其是自己写爬虫玩的时候,peewee + SQLite 已经成了我的标配。

准备写一个 peewee 的系列文章,本篇讲“增删改查”,本来应该是这个系列的第二篇,第一篇讲“建模”。这篇是年前就写好的,一直没发,本想等第一篇写好了以后按顺序发的,奈何年后几个项目并行,加班开始,这第一篇就要拖一拖了,先把这第二篇发出来,公众号也好久没发文了。最后给大家拜个晚年!

说明:peewee中有很多方法是延时执行的,需要调用 方法使其立即执行。下文中不再特意说明这个问题,大家看代码。

本文中代码样例所使用的Person模型如下:

一、新增

1、create

向数据库中插入一条记录,并返回一个新的实例。

2、save

语法:

参数:

force_insert:是否强制插入

only(list):需要持久化的字段,当提供此参数时,只有提供的字段被持久化。

示例:

这里说的比较简单,下面会详细说明。

3、insert

只插入数据而不创建模型实例,返回新行的主键。

4、insert_many

语法:

参数:

rows:元组或字典列表,要插入的数据

fields(list):需要插入的字段名列表。

说明:

1、当 rows 传递的是字典列表时,fields 是不需要传的,如果传了,那么,rows 中的字段在字典中必须存在,否则报错。如果没有传递 fields 参数,那么默认取所有字典的交集作为插入字段。这个也好理解,比如一个字典的键是,一个是 ,那么就取 作为需要插入的字段。peewee不会为缺失的字段做默认处理。

2、当 rows 传递的是元组列表时,必须指定 fields,并且 fields 中字段名的顺序跟元组一致。元组中值的数量必须大于等于 fields 中字段的数量,一般建议是保持一致。

示例:

对于批量操作,应该放在事务中执行:

在使用批量插入时,如果是 SQLite,SQLite3 版本必须为 3.7.11.0 或更高版本才能利用批量插入API。此外,默认情况下,SQLite 将 SQL 查询中的绑定变量数限制为 999。

SQLite 中,当批量插入的行数超过 999 时,就需要使用循环来将数据批量分组:

Peewee中带有一个分块辅助函数 ,使用它可以有效地将通用迭代块分块为一系列批量迭代的迭代:

5、bulk_create

语法:

参数:

model_list (iterable):未保存的模型实例的列表或其他可迭代对象。

batch_size (int):每次批量插入的行数。如果未指定,则一次性全部插入。

示例:

简单来说, 使用字典或元组列表作为参数,而 使用模型实例列表作为参数,就这区别。

注意:如果使用的是 Postgresql(支持该RETURNING子句),则先前未保存的模型实例将自动填充其新的主键值。

例如用的是 SQLite,执行上述代码之后, 显示的结果是 。

6、batch_commit

这不是一个好的方法,来看下面的例子

查看 SQL 语句如下:

其实, 就是自动添加了一个事务,然后一条条的插入,所以返回的模型实例中能获取到主键。

参数第一个是字典列表,第二个就是每多少条启用一个事务,大家可以把它改成 1 看下 SQL 语句就明白了。

7、insert_from

使用SELECT查询作为源INSERT数据。此 API 应用于INSERT INTO … SELECT FROM …形式的查询。

语法:

参数:

query:SELECT查询用作数据源

fields:要将数据插入的字段,此参数必须要的

示例:我们将 Person 表按原结构复制一个 Person2 表出来,以做演示。

注意:因为是INSERT INTO … SELECT FROM …形式的,所以数据源的列跟要插入的列必须保持一致。

二、删除

1、delete

后加 删除指定记录,如果不加 ,则删除全部记录。

2、delete_instance

删除给定的实例。

语法:

示例:

直接执行删除了,不用调用 方法。

参数:

一般我都是先讲参数再讲示例的,这次倒过来,示例其实很简单,一看就明白。但是这个参数缺需要好好讲下。

这两个参数都跟外键有关。我们修改一下测试用的模型。假设有这样两个模型,一个人员,一个部门,人员属于部门。

① 当 时,只删除了【部门】,【人员】没有影响,从 SQL 语句中可以看出。

② 当 ,并且外键不可为空时,会先删除【部门】下的【人员】,再删除【部门】。

③ 当 ,并且外键可为空时,先将【人员】的【部门ID(外键字段)】置为了NULL,再删除【部门】。

④ 仅在 且外键可为空时有效,和 ③ 一样,当 时,会删除【人员】,而不是将【人员的部门ID】置为NULL。

三、修改

1、save

之前说过, 方法可以插入一条记录,一旦模型实例具有主键,任何后续调用 都将导致UPDATE而不是另一个INSERT。模型的主键不会改变。

这个例子,第一次执行的 是INSERT,第二次是UPDATE。

这里解释一下, 这个模型,我并没有指定主键,peewee会自动增加一个名为id的自增列作为主键。在执行第一个 方法的时候,主键没值,所以执行INSERT, 方法执行之后,自增列的值就返回并赋给了模型实例,所以第二次调用 执行的是UPDATE。

如果模型中一开始就用 或 指定了主键,那么 执行的永远都是 ,所以什么主键不存在则INSERT,存在则UPDATE这种操作根本不存在,只能自己来写判断。

2、update

用于批量更新,方法相对简单,以下三种写法都可以

3、原子更新

看这样的一个需求,有一张表,记录博客的访问量,每次有人访问博客的时候,访问量+1。

因为懒得新建模型,我们就以 Person 模型的 Age + 1 来演示。

我们可以这样来写:

这样当然是可以实现的,但是这不仅速度慢,而且如果多个进程同时更新计数器,它也容易受到竞争条件的影响。

我们可以用 方法来实现。

四、查询

1、get

方法检索与给定查询匹配的单个实例。

语法:

参数:

query:查询条件

filters:Mapping of field-name to value for Django-style filter. 我翻遍网上文章和官方文档都没找到这玩意怎么用!

示例:

或者

当获取的结果不存在时,报 异常。如果有多条记录满足条件,则返回第一条。

2、get_or_none

如果当获取的结果不存在时,不想报错,可以使用 方法,会返回 ,参数和 方法一致。

3、get_by_id

对于主键查找,还可以使用快捷方法。

4、get_or_create

Peewee有一个辅助方法来执行“获取/创建”类型的操作: 首先尝试检索匹配的行。如果失败,将创建一个新行。

参数:

的参数是 ,其中 defaults 为非查询条件的参数,剩余的为尝试检索匹配的条件,这个看执行时的 SQL 语句就一目了然了。对于“创建或获取”类型逻辑,通常会依赖唯一 约束或主键来防止创建重复对象。但这并不是强制的,比如例子中,我以 为条件,而 并非主键。只是最好不要这样做。

返回值:

方法有两个返回值,第一个是“获取/创建”的模型实例,第二个是是否新创建。

5、select

使用 查询获取多条数据。 后可以添加 条件,如果不加则查询整个表。

语法:

参数:

fields:需要查询的字段,不传时返回所有字段。传递方式如下例所示。

示例:

返回结果是一个 对象,该对象可迭代、索引、切片。当查询不到结果时,不报错,返回 。并且 结果是延时返回的。如果想立即执行,可以调用 方法。

注意:中的条件不支持 这种写法,只能是 。

6、获取记录条数 count 方法

使用 方法可以获取记录条数。

也许你会问,用 方法可以吗?当然也是可以的,但是是一种不可取的方法。

这两者的实现方式天差地远。用 方法,执行的SQL语句是:

而用 方法执行的SQL语句却是:

直接返回所有记录然后获取长度,这种方法是非常不可取的。

7、排序 order_by 方法

排序默认是升序排列,也可以用 或 来明确表示是升序排列:

用 或 来表示降序:

如要对多个字段进行排序,逗号分隔写就可以了。

五、查询条件

当查询条件不止一个,需要使用逻辑运算符连接,而 Python 中的 、 在 Peewee 中是不支持的,此时我们需要使用 Peewee 封装好的运算符,如下:

特别注意:有多个条件时,每个条件必须用 () 括起来。

当条件全为and时,也可以用逗号分隔,get和select中都可以:

六、支持的比较符

注意:由于 SQLite 的 LIKE 操作默认情况下不区分大小写,因此 peewee 将使用 SQLite GLOB 操作进行区分大小写的搜索。glob 操作使用星号表示通配符,而不是通常的百分号。如果您正在使用 SQLite 并希望区分大小写的部分字符串匹配,请记住使用星号作为通配符。

解释一下,在 SQLite 中,如果希望 like 的时候区分大小写,可以这么写:

如果不希望区分大小写,这么写:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190215G08VCU00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券