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

文章目录

      • [12.2.11 class TableFunction](#12.2.11 class TableFunction)
      • [12.2.12 ClosureTable](#12.2.12 ClosureTable)
      • [12.2.13 class BaseClosureTable](#12.2.13 class BaseClosureTable)

12.2.11 class TableFunction

python 复制代码
class TableFunction

实现用户定义的表值函数。与返回单个标量值的简单 标量或聚合函数不同,表值函数可以返回任意数量的表格数据行。

简单的例子:

python 复制代码
from playhouse.sqlite_ext import TableFunction


class Series(TableFunction):
    # Name of columns in each row of generated data.
    columns = ['value']

    # Name of parameters the function may be called with.
    params = ['start', 'stop', 'step']

    def initialize(self, start=0, stop=None, step=1):
        """
        Table-functions declare an initialize() method, which is
        called with whatever arguments the user has called the
        function with.
        """
        self.start = self.current = start
        self.stop = stop or float('Inf')
        self.step = step

    def iterate(self, idx):
        """
        Iterate is called repeatedly by the SQLite database engine
        until the required number of rows has been read **or** the
        function raises a `StopIteration` signalling no more rows
        are available.
        """
        if self.current > self.stop:
            raise StopIteration

        ret, self.current = self.current, self.current + self.step
        return (ret,)

# Register the table-function with our database, which ensures it
# is declared whenever a connection is opened.
db.table_function('series')(Series)

# Usage:
cursor = db.execute_sql('SELECT * FROM series(?, ?, ?)', (0, 5, 2))
for value, in cursor:
    print(value)

笔记

ATableFunction必须先注册到database连接才能使用。为确保表函数始终可用,您可以使用 SqliteDatabase.table_function()装饰器将函数注册到database。

TableFunction实现必须提供两个属性并实现两个方法,如下所述。

columns

一个列表,其中包含函数返回的数据的列名。例如,用于在分隔符上拆分字符串的函数可能指定 3 列:.[substring, start_idx, end_idx]

params

可以调用函数的参数的名称。应列出所有参数,包括可选参数。例如,用于在分隔符上拆分字符串的函数可能指定 2 个参数:。[string, delimiter]

name

可选- 指定表函数的名称。如果未提供,名称将取自类名。

print_tracebacks = True

打印表函数回调方法中发生的任何错误的完整回溯。当设置为 False 时,只有通用 OperationalError 可见。

initialize( **parameter_values )

参数: 参数值-- 调用函数的参数。

返回: 没有返回值。

调用该initialize方法以使用用户在调用函数时指定的参数初始化表函数。

iterate( idx )

参数: 编号( int ) - 当前迭代步骤

返回: 对应于columns属性中命名的列的行数据元组。

提高: 停止迭代-- 表示没有更多行可用。

该函数被重复调用并返回连续的数据行。该函数可能会在所有行被消耗之前终止(特别是如果用户LIMIT在结果上指定了 a )。或者,该函数可以通过引发 StopIteration异常来表示没有更多数据可用。

classname register(conn)

参数: conn-- 一个sqlite3.Connection对象。

sqlite3.Connection 使用 DB-API 2.0对象注册表函数。表值函数必须先注册,然后才能在查询中使用。

例子:

python 复制代码
class MyTableFunction(TableFunction):
    name = 'my_func'
    # ... other attributes and methods ...

db = SqliteDatabase(':memory:')
db.connect()

MyTableFunction.register(db.connection())

为了确保TableFunction每次打开连接时都注册,请使用table_function() 装饰器。

12.2.12 ClosureTable

python 复制代码
ClosureTable(model_class[, foreign_key=None[, referencing_class=None[, referencing_key=None]]])

参数:

  • model_class -- 包含树中节点的模型类。
  • foreign_key -- 模型类上的自引用父节点字段。如果未提供,peewee 将自省模型以找到合适的密钥。
  • referencing_class -- 多对多关系的中间表。
  • referenceencing_key -- 对于多对多关系,关系的发起方。
    返回:
    返回一个VirtualModel用于处理闭包表。

用于创建适用于 传递闭包 表的模型类的工厂函数。闭包表是VirtualModel与传递闭包 SQLite 扩展一起使用的子类。这些特殊表旨在使高效查询分层数据变得容易。SQLite 扩展在幕后管理 AVL 树,当您的表发生更改时透明地更新树,并使对分层数据执行常见查询变得容易。

要在项目中使用闭包表扩展,您需要:

SQLite 扩展的副本。可以在SQLite 代码存储库中找到源代码,也可以 通过克隆以下 gist找到源代码:

python 复制代码
$ git clone https://gist.github.com/coleifer/7f3593c5c2a645913b92 closure
$ cd closure/

将扩展编译为共享库,例如

python 复制代码
$ gcc -g -fPIC -shared closure.c -o closure.so

为您的分层数据创建模型。这里唯一的要求是模型有一个整数主键和一个自引用外键。任何其他字段都可以。

python 复制代码
class Category(Model):
    name = CharField()
    metadata = TextField()
    parent = ForeignKeyField('self', index=True, null=True)  # Required.

# Generate a model for the closure virtual table.
CategoryClosure = ClosureTable(Category)

自引用也可以通过中间表(对于多对多关系)来实现。

python 复制代码
class User(Model):
    name = CharField()

class UserRelations(Model):
    user = ForeignKeyField(User)
    knows = ForeignKeyField(User, backref='_known_by')

    class Meta:
        primary_key = CompositeKey('user', 'knows') # Alternatively, a unique index on both columns.

# Generate a model for the closure virtual table, specifying the UserRelations as the referencing table
UserClosure = ClosureTable(
    User,
    referencing_class=UserRelations,
    foreign_key=UserRelations.knows,
    referencing_key=UserRelations.user)

在您的应用程序代码中,确保在实例化Database对象时加载扩展。这是通过将共享库的路径传递给load_extension()方法来完成的。

python 复制代码
db = SqliteExtDatabase('my_database.db')
db.load_extension('/path/to/closure')

警告

transitive_closure使用扩展程序时,您应该注意两个警告 。首先,它要求您的源模型具有整数主键。其次,强烈建议您在自引用外键上创建索引。

例子:

python 复制代码
class Category(Model):
    name = CharField()
    metadata = TextField()
    parent = ForeignKeyField('self', index=True, null=True)  # Required.

# Generate a model for the closure virtual table.
CategoryClosure = ClosureTable(Category)

 # Create the tables if they do not exist.
 db.create_tables([Category, CategoryClosure], True)

现在可以使用闭包表中的数据执行有趣的查询:

python 复制代码
# Get all ancestors for a particular node.
laptops = Category.get(Category.name == 'Laptops')
for parent in Closure.ancestors(laptops):
    print(parent.name)

# Computer Hardware
# Computers
# Electronics
# All products

# Get all descendants for a particular node.
hardware = Category.get(Category.name == 'Computer Hardware')
for node in Closure.descendants(hardware):
    print(node.name)

# Laptops
# Desktops
# Hard-drives
# Monitors
# LCD Monitors
# LED Monitors

由 VirtualModel.返回的API ClosureTable()。

12.2.13 class BaseClosureTable

python 复制代码
class BaseClosureTable

id

给定节点的主键字段。

depth

表示给定节点的相对深度的字段。

root

表示相对根节点的字段。

descendants(node[, depth=None[, include_node=False]])

检索给定节点的所有后代。如果指定了深度,则仅返回该深度(相对于给定节点)的节点。

python 复制代码
node = Category.get(Category.name == 'Electronics')

# Direct child categories.
children = CategoryClosure.descendants(node, depth=1)

# Grand-child categories.
children = CategoryClosure.descendants(node, depth=2)

# Descendants at all depths.
all_descendants = CategoryClosure.descendants(node)

ancestors(node[, depth=None[, include_node=False]])

检索给定节点的所有祖先。如果指定了深度,则仅返回该深度(相对于给定节点)的节点。

python 复制代码
node = Category.get(Category.name == 'Laptops')

# All ancestors.
all_ancestors = CategoryClosure.ancestors(node)

# Grand-parent category.
grandparent = CategoryClosure.ancestores(node, depth=2)

siblings(node[, include_node=False])

检索作为指定节点父节点的子节点的所有节点。

笔记

有关 SQLite 传递闭包扩展的深入讨论,请查看这篇博文,使用 Python 和传递闭包扩展查询 SQLite 中的树结构。

相关推荐
吕彬-前端11 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱14 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai23 分钟前
uniapp
前端·javascript·vue.js·uni-app
狂奔solar33 分钟前
yelp数据集上识别潜在的热门商家
开发语言·python
Tassel_YUE34 分钟前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
聪明的墨菲特i41 分钟前
Python爬虫学习
爬虫·python·学习
CopyDragon1 小时前
设置域名跨越访问
数据库·sqlite
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
努力的家伙是不讨厌的2 小时前
解析json导出csv或者直接入库
开发语言·python·json