>>> from env_helper import info; info()
页面更新时间: 2024-04-07 23:42:19
运行环境:
Linux发行版本: Debian GNU/Linux 12 (bookworm)
操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
Python版本: 3.11.2
2.8. 使用 Peewee 扩展 SQLite 的使用¶
默认值 SqliteDatabase 已经包含许多特定于sqlite的功能:
有关使用SQLite的一般说明 .
使用PRAGMA语句配置SQLite.
用户定义的函数,聚合和排序规则 .
交易锁定模式 .
这个 playhouse.sqlite_ext 包括更多的sqlite功能,包括:
全文搜索.
JSON扩展集成.
闭包表扩展支持.
LSM1扩展支持.
用户定义表功能.
使用备份API支持联机备份: backup_to_file()
BLOB API支持,用于高效的二进制数据存储. .
其他帮助, 包括布卢姆过滤器,更多。
class JSONField(json_dumps=None, json_loads=None, ...)
适用于存储JSON数据的字段类,具有设计用于 json1 extension .
2.8.1. 介绍¶
添加了sqlite 3.9.0扩展库形式的JSON支持。 SQLite json1扩展提供了许多用于处理JSON数据的辅助函数。 这些API作为特殊字段类型JSONField的方法公开。
要访问或修改JSON结构中的特定对象键或数组索引,可以处理 JSONField 就像是一本字典、一张清单。
参数
json_dumps
–
(可选)用于将数据序列化为JSON字符串的函数。如果没有提供,将使用stdlib
json.dumps .
json_loads
–
(可选)用于将JSON反序列化为Python对象的函数。如果没有提供,将使用stdlib
json.loads .
注解
要自定义JSON序列化或反序列化,可以指定自定义 json_dumps 和 json_loads 召唤物。这些函数应该分别接受一个参数:要序列化的对象和JSON字符串。要修改stdlib json函数的参数,可以使用 functools.partial :
# 不要转义unicode代码点。
my_json_dumps = functools.partial(json.dumps, ensure_ascii=False)
class SomeModel(Model):
# 指定我们的自定义序列化功能。
json_data = JSONField(json_dumps=my_json_dumps)
2.8.2. 实例说明¶
让我们来看一些使用sqlite json1扩展和peewee的例子。在这里,我们将准备一个数据库和一个简单的模型来测试 json1 extension :
>>> from playhouse.sqlite_ext import *
>>> db = SqliteExtDatabase(':memory:')
>>> class KV(Model):
>>> key = TextField()
>>> value = JSONField()
>>> class Meta:
>>> database = db
>>> KV.create_table()
存储数据可以按预期工作。无需将字典或列表序列化为json,因为这是由peewee自动完成的:
>>> KV.create(key='a', value={'k1': 'v1'})
<KV: 1>
>>> KV.get(KV.key == 'a').value
{'k1': 'v1'}
我们可以使用字典查找访问JSON数据的特定部分:
>>> KV.get(KV.value['k1'] == 'v1').key
'a'
可以使用 update()
方法。注意“k1=v1”保留:
>>> KV.update(value=KV.value.update({'k2': 'v2', 'k3': 'v3'})).execute()
1
>>> KV.get(KV.key == 'a').value
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
我们还可以自动更新现有数据,或者通过将键的值设置为来删除键。在下面的示例中,我们将更新“k1”的值并删除“k3”(“k2”不会被修改):
>>> KV.update(value=KV.value.update({'k1': 'v1-x', 'k3': None})).execute()
1
>>> KV.get(KV.key == 'a').value
{'k1': 'v1-x', 'k2': 'v2'}
我们还可以使用 set()
方法:
>>> KV.update(value=KV.value['k1'].set('v1')).execute()
1
>>> KV.get(KV.key == 'a').value
{'k1': 'v1', 'k2': 'v2'}
这个 set()
除了标量值之外,方法还可以用于对象:
>>> KV.update(value=KV.value['k2'].set({'x2': 'y2'})).execute()
1
>>> KV.get(KV.key == 'a').value
{'k1': 'v1', 'k2': {'x2': 'y2'}}
也可以使用原子方式删除JSON数据的各个部分。 remove()
:
>>> KV.update(value=KV.value['k2'].remove()).execute()
1
>>> KV.get(KV.key == 'a').value
{'k1': 'v1'}
我们还可以使用 json_type()
方法:
>>> KV.select(KV.value.json_type(), KV.value['k1'].json_type()).tuples()[:]
[('object', 'text')]
让我们添加一个嵌套值,然后看看如何使用 tree()
方法:
>>> KV.create(key='b', value={'x1': {'y1': 'z1', 'y2': 'z2'}, 'x2': [1, 2]})
<KV: 2>
>>> tree = KV.value.tree().alias('tree')
>>> query = KV.select(KV.key, tree.c.fullkey, tree.c.value).from_(KV, tree)
>>> query.tuples()[:]
[('a', '$', {'k1': 'v1'}),
('a', '$.k1', 'v1'),
('b', '$', {'x1': {'y1': 'z1', 'y2': 'z2'}, 'x2': [1, 2]}),
('b', '$.x1', {'y1': 'z1', 'y2': 'z2'}),
('b', '$.x1.y1', 'z1'),
('b', '$.x1.y2', 'z2'),
('b', '$.x2', [1, 2]),
('b', '$.x2[0]', 1),
('b', '$.x2[1]', 2)]
这个 tree()
和 children()
方法是强大的。有关如何使用它们的详细信息,请参阅 json1 extension
documentation .
还要注意的是 JSONField 查找可以链接:
>>> query = KV.select().where(KV.value['x1']['y1'] == 'z1')
>>> for obj in query:
>>> print(obj.key, obj.value)
b {'x1': {'y1': 'z1', 'y2': 'z2'}, 'x2': [1, 2]}
有关详细信息,请参阅 sqlite json1 documentation .
2.8.3. 接口说明¶
__getitem__(item)
:参数item
是访问JSON数据中的特定键或数组索引。函数返回公开对JSON数据访问的特殊对象。返回类型JSONPath
.
访问JSON数据中的特定键或数组索引。返回A JSONPath 对象,它公开了读取或修改JSON对象特定部分的方便方法。
例子:
# If metadata contains {"tags": ["list", "of", "tags"]}, we can
# extract the first tag in this way:
Post.select(Post, Post.metadata['tags'][0].alias('first_tag'))
set(value[, as_json=None])
: 参数 value
,
标量值、列表或字典。as_json (bool)
,强制将该值视为JSON,在这种情况下,它将在python中预先序列化为JSON。默认情况下,列表和字典被视为要序列化的JSON,而字符串和整数则按原样传递。
设置存储在 JSONField .使用 json_set()
来自JSON1扩展的函数。
update(data)
:参数data
, 要与当前存储在 JSONField .
要删除特定的密钥,请将该密钥设置为 None 在更新的数据中。
使用RFC-7396 merge patch算法将新数据合并到json值中以应用补丁( data
参数)。MergePatch可以添加、修改或删除JSON对象的元素,这意味着
update()
是两者的通用替换 set()
和 remove()
.
MergePatch将JSON数组对象视为原子对象,因此 update()
不能追加到数组,也不能修改数组的单个元素。
RFC-7396:该规范定义了JSON合并补丁程序格式和处理规则。 合并修补程序格式主要用于HTTP PATCH方法,作为描述对目标资源内容的一组修改的一种方式。
remove()
:删除存储在 JSONField .使用 json_remove
来自JSON1扩展的函数。
json_type()
:
返回一个标识列中存储的值类型的字符串。返回的类型将是以下类型之一:
对象;数组;整数;真实的;真;假;文本;null,字符串“空”表示实际的空值;None,实际空值表示找不到路径 。
使用 json_type 来自JSON1扩展的函数。
length()
: 返回存储在列中的数组的长度。 使用 json_array_length
来自JSON1扩展的函数。
children()
: 这个 children 函数对应于 json_each
,一个表值函数,用于遍历所提供的JSON值并返回顶级数组或对象的直接子级。如果指定了路径,则该路径将被视为最上面的元素。
调用返回的行 children()
具有以下属性:
key :当前元素相对于其父元素的键。
value :当前元素的值。
type :数据类型之一(请参见 json_type() )
atom :基元类型的标量值, NULL 用于数组和对象。
id :引用树中当前节点的唯一ID。
parent :包含节点的ID。
fullkey :描述当前元素的完整路径。
path :当前行的容器路径。
在内部,此方法使用 json_each (文档链接)json1扩展中的函数。
示例用法与 tree()
方法:
>>> from playhouse.sqlite_ext import *
>>> db = SqliteExtDatabase('keyd')
>>> class KeyData(Model):
>>> key = TextField()
>>> data = JSONField()
>>> class Meta:
>>> database = db
>>> KeyData.create_table()
>>> KeyData.create(key='a', data={'k1': 'v1', 'x1': {'y1': 'z1'}})
>>> KeyData.create(key='b', data={'x1': {'y1': 'z1', 'y2': 'z2'}})
<KeyData: 4>
我们将在KeyData模型中查询键以及其数据字段中的所有顶级键和值。
>>> kd = KeyData.data.children().alias('children')
>>> query = (KeyData
>>> .select(kd.c.key, kd.c.value, kd.c.fullkey)
>>> .from_(KeyData, kd)
>>> .order_by(kd.c.key)
>>> .tuples())
>>> print(query[:])
[('k1', 'v1', '$.k1'), ('k1', 'v1', '$.k1'), ('x1', '{"y1":"z1"}', '$.x1'), ('x1', '{"y1":"z1","y2":"z2"}', '$.x1'), ('x1', '{"y1":"z1"}', '$.x1'), ('x1', '{"y1":"z1","y2":"z2"}', '$.x1')]
这个 tree()
函数对应于 json_tree
,一个表值函数,它递归地遍历所提供的JSON值,并返回有关每个级别的键的信息。如果指定了路径,则该路径将被视为最上面的元素。
调用返回的行 tree()
具有与调用返回的行相同的属性 children()
:
key :当前元素相对于其父元素的键。
value :当前元素的值。
type :数据类型之一(请参见 json_type() )
atom :基元类型的标量值, NULL 用于数组和对象。
id :引用树中当前节点的唯一ID。
parent :包含节点的ID。
fullkey :描述当前元素的完整路径。
path :当前行的容器路径。
在内部,此方法使用 json_tree (文档链接)json1扩展中的函数。
示例用法:
>>> from playhouse.sqlite_ext import *
>>> db = SqliteExtDatabase('keyd2')
>>> class KeyData2(Model):
>>> key = TextField()
>>> data = JSONField()
>>> class Meta:
>>> database = db
>>> KeyData2.create_table()
>>> KeyData2.create(key='a', data={'k1': 'v1', 'x1': {'y1': 'z1'}})
>>> KeyData2.create(key='b', data={'x1': {'y1': 'z1', 'y2': 'z2'}})
<KeyData2: 4>
我们将递归地查询KeyData2模型中的键以及其数据字段中的所有键和值。
>>> kd = KeyData2.data.tree().alias('tree')
>>> query = (KeyData2.select(kd.c.key, kd.c.value, kd.c.fullkey)
>>> .from_(KeyData2, kd)
>>> .order_by(kd.c.key)
>>> .tuples())
>>> print(query[:])
[(None, '{"k1":"v1","x1":{"y1":"z1"}}', '$'), (None, '{"x1":{"y1":"z1","y2":"z2"}}', '$'), (None, '{"k1":"v1","x1":{"y1":"z1"}}', '$'), (None, '{"x1":{"y1":"z1","y2":"z2"}}', '$'), ('k1', 'v1', '$.k1'), ('k1', 'v1', '$.k1'), ('x1', '{"y1":"z1"}', '$.x1'), ('x1', '{"y1":"z1","y2":"z2"}', '$.x1'), ('x1', '{"y1":"z1"}', '$.x1'), ('x1', '{"y1":"z1","y2":"z2"}', '$.x1'), ('y1', 'z1', '$.x1.y1'), ('y1', 'z1', '$.x1.y1'), ('y1', 'z1', '$.x1.y1'), ('y1', 'z1', '$.x1.y1'), ('y2', 'z2', '$.x1.y2'), ('y2', 'z2', '$.x1.y2')]