【Python百日进阶-Web开发-Peewee】Day277 - SQLite 扩展(二)

文章目录

      • 12.2.6 class JSONField

12.2.6 class JSONField

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()

返回一个字符串,标识存储在列中的值的类型。

返回的类型将是以下之一:

  • object
  • array
  • integer
  • real
  • true
  • false
  • text
  • null <– 字符串“null”表示实际的 NULL 值
  • NULL <– 实际的 NULL 值表示未找到路径
    使用 json1 扩展中的json_type 函数。

length()

返回存储在列中的数组的长度。

使用 json1 扩展中的json_array_length 函数。

children()

该children函数对应于json_each,一个表值函数,它遍历提供的 JSON 值并返回顶级数组或对象的直接子级。如果指定了路径,则该路径被视为最顶层元素。

调用返回的行children()具有以下属性:

  • key:当前元素相对于其父元素的键。
  • value:当前元素的值。
  • type: 一种数据类型(参见 参考资料json_type())。
  • atom:原始类型、NULL数组和对象的标量值。
  • id: 引用树中当前节点的唯一 ID。
  • parent: 包含节点的 ID。
  • fullkey:描述当前元素的完整路径。
  • path: 当前行的容器的路径。
    在内部,此方法使用 json1 扩展中的json_each (文档链接)函数。

示例用法(与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():

  • key:当前元素相对于其父元素的键。
  • value:当前元素的值。
  • type: 一种数据类型(参见 参考资料json_type())。
  • atom:原始类型、NULL数组和对象的标量值。
  • id: 引用树中当前节点的唯一 ID。
  • parent: 包含节点的 ID。
  • fullkey:描述当前元素的完整路径。
  • path: 当前行的容器的路径。
    在内部,此方法使用 json1 扩展中的json_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
# 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')]

你可能感兴趣的:(数据库,python,sqlite)