class JSONField( json_dumps=None , json_loads=None , ... )
适合存储 JSON 数据的字段类,具有旨在与json1 扩展一起使用的特殊方法。
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:
# Do not escape unicode code-points.
my_json_dumps = functools.partial(json.dumps, ensure_ascii=False)
class SomeModel(Model):
# Specify our custom serialization function.
json_data = JSONField(json_dumps=my_json_dumps)
让我们看一些将 SQLite json1 扩展与 Peewee 一起使用的示例。在这里,我们将准备一个database和一个简单的模型来测试 json1 扩展:
>>> 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() 可以使用该方法就地更新 JSON 值。请注意,“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'}
我们还可以自动更新现有数据,或者通过将键的值设置为来删除键None。在以下示例中,我们将更新“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()我们还可以使用以下方法设置 JSON 数据的各个部分:
>>> 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 数据中特定位置的值的类型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', '$.x2', [1, 2]),
('b', '$.x2[0]', 1),
('b', '$.x2[1]', 2),
('b', '$.x1', {'y1': 'z1', 'y2': 'z2'}),
('b', '$.x1.y1', 'z1'),
('b', '$.x1.y2', 'z2')]
children()和tree()方法很强大。有关如何使用它们的更多信息,请参阅 json1 扩展文档。
另请注意,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 文档。
getitem(item)
参数: 物品– 访问 JSON 数据中的特定键或数组索引。
返回: 公开访问 JSON 数据的特殊对象。
返回类型: JSON路径
访问 JSON 数据中的特定键或数组索引。返回一个 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'))
有关更多示例,请参阅JSONPathAPI 文档。
set(value[, as_json=None])
参数:
value – 标量值、列表或字典。
as_json ( bool ) – 强制将值视为 JSON,在这种情况下,它将预先在 Python 中序列化为 JSON。默认情况下,列表和字典被视为要序列化的 JSON,而字符串和整数则按原样传递。
设置存储在 a 中的值JSONField。
使用 json1 扩展中的json_set()函数。
update(value)
参数: 数据– 一个标量值、列表或字典,用于与当前存储在 a 中的数据合并JSONField。要删除特定键,请将该键设置None为更新的数据中。
使用 RFC-7396 MergePatch 算法将新数据合并到 JSON 值中,以data针对列数据应用补丁(参数)。MergePatch 可以添加、修改或删除 JSON 对象的元素,这意味着它是和update()的通用替换。MergePatch 将 JSON 数组对象视为原子对象,因此不能附加到数组,也不能修改数组的单个元素。set()remove()update()
有关更多信息和示例,请参阅 SQLite json_patch() 函数文档。
remove()
删除存储在JSONField.
使用 json1 扩展中的json_remove函数。
json_type()
返回一个字符串,标识存储在列中的值的类型。
返回的类型将是以下之一:
length()
返回存储在列中的数组的长度。
使用 json1 扩展中的json_array_length 函数。
children()
该children函数对应于json_each,一个表值函数,它遍历提供的 JSON 值并返回顶级数组或对象的直接子级。如果指定了路径,则该路径被视为最顶层元素。
调用返回的行children()具有以下属性:
示例用法(与tree()方法比较):
class KeyData(Model):
key = TextField()
data = JSONField()
KeyData.create(key='a', data={'k1': 'v1', 'x1': {'y1': 'z1'}})
KeyData.create(key='b', data={'x1': {'y1': 'z1', 'y2': 'z2'}})
# We will query the KeyData model for the key and all the
# top-level keys and values in it's data field.
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[:])
# PRINTS:
[('a', 'k1', 'v1', '$.k1'),
('a', 'x1', '{"y1":"z1"}', '$.x1'),
('b', 'x1', '{"y1":"z1","y2":"z2"}', '$.x1')]
tree()
该tree函数对应于json_tree一个表值函数,它递归地遍历提供的 JSON 值并返回有关每个级别的键的信息。如果指定了路径,则该路径被视为最顶层元素。
调用返回的行与调用返回的行tree()具有相同的属性children():
示例用法:
class KeyData(Model):
key = TextField()
data = JSONField()
KeyData.create(key='a', data={'k1': 'v1', 'x1': {'y1': 'z1'}})
KeyData.create(key='b', data={'x1': {'y1': 'z1', 'y2': 'z2'}})
# We will query the KeyData model for the key and all the
# keys and values in it's data field, recursively.
kd = KeyData.data.tree().alias('tree')
query = (KeyData
.select(kd.c.key, kd.c.value, kd.c.fullkey)
.from_(KeyData, kd)
.order_by(kd.c.key)
.tuples())
print(query[:])
# PRINTS:
[('a', None, '{"k1":"v1","x1":{"y1":"z1"}}', '$'),
('b', None, '{"x1":{"y1":"z1","y2":"z2"}}', '$'),
('a', 'k1', 'v1', '$.k1'),
('a', 'x1', '{"y1":"z1"}', '$.x1'),
('b', 'x1', '{"y1":"z1","y2":"z2"}', '$.x1'),
('a', 'y1', 'z1', '$.x1.y1'),
('b', 'y1', 'z1', '$.x1.y1'),
('b', 'y2', 'z2', '$.x1.y2')]