返回顶部
首页 > 资讯 > 精选 >Tortoise orm信号实现及使用场景是什么
  • 504
分享到

Tortoise orm信号实现及使用场景是什么

2023-07-05 12:07:24 504人浏览 泡泡鱼
摘要

今天小编给大家分享一下Tortoise ORM信号实现及使用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。场景在使

今天小编给大家分享一下Tortoise ORM信号实现及使用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    场景

    在使用Tortoise操作数据库的时候发现,通过对操作数据库模型加以装饰器,如@pre_save(Model),可以实现对这个模型在saVue时,自动调用被装饰的方法,从而实现对模型的一些操作。

    在此先从官方文档入手,看一下官方的对于模型信号的Example

    # -*- coding: utf-8 -*-"""This example demonstrates model signals usage"""from typing import List, Optional, Typefrom tortoise import BaseDBAsyncClient, Tortoise, fields, run_asyncfrom tortoise.models import Modelfrom tortoise.signals import post_delete, post_save, pre_delete, pre_saveclass Signal(Model):    id = fields.IntField(pk=True)    name = fields.TextField()    class Meta:        table = "signal"    def __str__(self):        return self.name@pre_save(Signal)async def signal_pre_save(    sender: "Type[Signal]", instance: Signal, using_db, update_fields) -> None:    print('signal_pre_save', sender, instance, using_db, update_fields)@post_save(Signal)async def signal_post_save(    sender: "Type[Signal]",    instance: Signal,    created: bool,    using_db: "Optional[BaseDBAsyncClient]",    update_fields: List[str],) -> None:    print('post_save', sender, instance, using_db, created, update_fields)@pre_delete(Signal)async def signal_pre_delete(    sender: "Type[Signal]", instance: Signal, using_db: "Optional[BaseDBAsyncClient]") -> None:    print('pre_delete', sender, instance, using_db)@post_delete(Signal)async def signal_post_delete(    sender: "Type[Signal]", instance: Signal, using_db: "Optional[BaseDBAsyncClient]") -> None:    print('post_delete', sender, instance, using_db)async def run():    await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})    await Tortoise.generate_schemas()    # pre_save,post_save will be send    signal = await Signal.create(name="Signal")    signal.name = "Signal_Save"    # pre_save,post_save will be send    await signal.save(update_fields=["name"])    # pre_delete,post_delete will be send    await signal.delete()if __name__ == "__main__":    run_async(run())

    以上代码可直接复制后运行,运行后的结果:

    signal_pre_save <class '__main__.Signal'> Signal <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400> None
    post_save <class '__main__.Signal'> Signal <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400> True None
    signal_pre_save <class '__main__.Signal'> Signal_Save <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400> ['name']
    post_save <class '__main__.Signal'> Signal_Save <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400> False ['name']
    pre_delete <class '__main__.Signal'> Signal_Save <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400>
    post_delete <class '__main__.Signal'> Signal_Save <tortoise.backends.sqlite.client.SqliteClient object at 0x7f8518319400>

    可以发现,对模型进行保存和删除时候,都会调用对应的信号方法。

    源码

    从导包可以得知,tortoise的所有信号方法都在tortoise.signals中。

    from enum import Enumfrom typing import CallableSignals = Enum("Signals", ["pre_save", "post_save", "pre_delete", "post_delete"])def post_save(*senders) -> Callable:    """    ReGISter given models post_save signal.    :param senders: Model class    """    def decorator(f):        for sender in senders:            sender.register_listener(Signals.post_save, f)        return f    return decoratordef pre_save(*senders) -> Callable:    ...def pre_delete(*senders) -> Callable:    ...def post_delete(*senders) -> Callable:    ...

    其内部实现的四个信号方法分别是模型的保存后,保存前,删除前,删除后。

    其内部装饰器代码也十分简单,就是对装饰器中的参数(也就是模型),注册一个监听者,而这个监听者,其实就是被装饰的方法。

    如上面的官方示例中:

    # 给模型Signal注册一个监听者,它是方法signal_pre_save@pre_save(Signal)async def signal_pre_save(    sender: "Type[Signal]", instance: Signal, using_db, update_fields) -> None:    print('signal_pre_save', sender, instance, using_db, update_fields)

    而到了Model类中,自然就有一个register_listener方法,定睛一看,上面示例Signal中并没有register_listener方法,所以自然就想到了,这个方法必定在父类Model中。

    class Model:    ...    @claSSMethod    def register_listener(cls, signal: Signals, listener: Callable):        ...        if not callable(listener):            raise ConfigurationError("Signal listener must be callable!")        # 检测是否已经注册过        cls_listeners = cls._listeners.get(signal).setdefault(cls, [])  # type:ignore        if listener not in cls_listeners:            # 注册监听者            cls_listeners.append(listener)

    接下来注册后,这个listeners就会一直跟着这个Signal类。只需要在需要操作关键代码的地方,进行调用即可。

    看看在模型save的时候,都干了什么?

        async def save(        self,        using_db: Optional[BaseDBAsyncClient] = None,        update_fields: Optional[Iterable[str]] = None,        force_create: bool = False,        force_update: bool = False,    ) -> None:        ...        # 执行保存前的信号        await self._pre_save(db, update_fields)        if force_create:            await executor.execute_insert(self)            created = True        elif force_update:            rows = await executor.execute_update(self, update_fields)            if rows == 0:                raise IntegrityError(f"Can't update object that doesn't exist. PK: {self.pk}")            created = False        else:            if self._saved_in_db or update_fields:                if self.pk is None:                    await executor.execute_insert(self)                    created = True                else:                    await executor.execute_update(self, update_fields)                    created = False            else:                # TODO: Do a merge/upsert operation here instead. Let the executor determine an optimal strategy for each DB engine.                await executor.execute_insert(self)                created = True        self._saved_in_db = True        # 执行保存后的信号        await self._post_save(db, created, update_fields)

    抛开其他代码,可以看到,在模型save的时候,其实是先执行保存前的信号,然后执行保存后的信号。

    自己实现一个信号

    有了以上的经验,可以自己实现一个信号,比如我打算做个数据处理器的类,我想在这个处理器工作中,监听处理前/后的信号。

    # -*- coding: utf-8 -*-from enum import Enumfrom typing import Callable, Dict# 声明枚举信号量Signals = Enum("Signals", ["before_process", "after_process"])# 处理前的装饰器def before_process(*senders):    def decorator(f):        for sender in senders:            sender.register_listener(Signals.before_process, f)        return f    return decorator# 处理后的装饰器def after_process(*senders):    def decorator(f):        for sender in senders:            sender.register_listener(Signals.after_process, f)        return f    return decoratorclass Model(object):    _listeners: Dict = {        Signals.before_process: {},        Signals.after_process: {}    }    @classmethod    def register_listener(cls, signal: Signals, listener: Callable):        """注册监听者"""        # 判断是否已经存在监听者        cls_listeners = cls._listeners.get(signal).setdefault(cls, [])        if listener not in cls_listeners:            # 如果不存在,则添加监听者            cls_listeners.append(listener)    def _before_process(self):        # 取出before_process监听者        cls_listeners = self._listeners.get(Signals.before_process, {}).get(self.__class__, [])        for listener in cls_listeners:            # 调用监听者            listener(self.__class__, self)    def _after_process(self):        # 取出after_process监听者        cls_listeners = self._listeners.get(Signals.after_process, {}).get(self.__class__, [])        for listener in cls_listeners:            # 调用监听者            listener(self.__class__, self)class SignalModel(Model):    def process(self):        """真正的调用端"""        self._before_process()        print("Processing")        self._after_process()# 注册before_process信号@before_process(SignalModel)def before_process_listener(*args, **kwargs):    print("before_process_listener1", args, kwargs)# 注册before_process信号@before_process(SignalModel)def before_process_listener(*args, **kwargs):    print("before_process_listener2", args, kwargs)# 注册after_process信号@after_process(SignalModel)def before_process_listener(*args, **kwargs):    print("after_process_listener", args, kwargs)if __name__ == '__main__':    sm = SignalModel()    sm.process()

    输出结果:

    before_process_listener1 (<class '__main__.SignalModel'>, <__main__.SignalModel object at 0x7ff700116e50>) {}
    before_process_listener2 (<class '__main__.SignalModel'>, <__main__.SignalModel object at 0x7ff700116e50>) {}
    Processing
    after_process_listener (<class '__main__.SignalModel'>, <__main__.SignalModel object at 0x7ff700116e50>) {}

    以上就是“Tortoise orm信号实现及使用场景是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: Tortoise orm信号实现及使用场景是什么

    本文链接: https://lsjlt.com/news/351739.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Tortoise orm信号实现及使用场景是什么
      今天小编给大家分享一下Tortoise orm信号实现及使用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。场景在使...
      99+
      2023-07-05
    • Tortoise-orm信号实现及使用场景源码详解
      目录场景源码看看在模型save的时候,都干了什么?自己实现一个信号总结场景 在使用Tortoise操作数据库的时候发现,通过对操作数据库模型加以装饰器,如@pre_save(Mod...
      99+
      2023-03-15
      Tortoise orm信号场景 Tortoise orm信号
    • RabbitMQ原理以及使用场景是什么
      本篇文章给大家分享的是有关RabbitMQ原理以及使用场景是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一. RabbitMQ 简介MQ...
      99+
      2024-04-02
    • JSON Schema概念及使用场景是什么
      本篇内容介绍了“JSON Schema概念及使用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.什么是JSON Sch...
      99+
      2023-07-02
    • RabbitMQ使用场景是什么
      这篇文章主要介绍“RabbitMQ使用场景是什么”,在日常操作中,相信很多人在RabbitMQ使用场景是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”RabbitMQ使用场景是什么”的疑惑有所帮助!接下来...
      99+
      2023-06-26
    • 什么是redis数据库,及其使用场景
      redis 是一种开源键值存储数据库,通过将数据存储在内存中提供极高的性能。它支持多种数据结构,例如字符串、哈希表、链表和集合。redis 的应用场景广泛,包括缓存、会话管理、消息传递、...
      99+
      2024-04-19
      redis
    • Java的引用类型及使用场景是什么
      这篇文章将为大家详细讲解有关Java的引用类型及使用场景是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java ...
      99+
      2023-06-14
    • Redis分布式锁怎么实现及应用场景是什么
      本篇内容介绍了“Redis分布式锁怎么实现及应用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!引言锁是开发过程中十分常见的工具,你...
      99+
      2023-06-29
    • Redis的使用场景是什么
      这篇文章主要介绍“Redis的使用场景是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Redis的使用场景是什么”文章能帮助大家解决问题。Redis常用命令总结:包括时间复杂度总结与具体数据类型...
      99+
      2023-06-02
    • Golang error使用场景是什么
      本篇内容主要讲解“Golang error使用场景是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang error使用场景是什么”吧!在Go的编程中, error...
      99+
      2023-07-05
    • ssl原理及应用场景是什么
      SSL(Secure Sockets Layer)是一种加密协议,用于保护在互联网上传输的数据安全。它使用公钥加密来保护数据的机密性...
      99+
      2023-06-12
      ssl原理 ssl
    • ArrayBlockQueue函数及应用场景是什么
      今天小编给大家分享一下ArrayBlockQueue函数及应用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。队列在...
      99+
      2023-07-05
    • vue使用slot的场景是什么
      这篇文章主要介绍“vue使用slot的场景是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue使用slot的场景是什么”文章能帮助大家解决问题。使用场景:通过slot(插槽)可以让用户可以拓展...
      99+
      2023-07-05
    • java SPI的使用场景是什么
      本文小编为大家详细介绍“java SPI的使用场景是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“java SPI的使用场景是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。概念SPI是服务提供界面,JD...
      99+
      2023-06-30
    • Confd和Consul使用场景是什么
      这篇文章主要介绍了Confd和Consul使用场景是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Confd和Consul使用场景是什么文章都会有所收获,下面我们一起来看看吧。Confd和Consul是什么...
      99+
      2023-07-05
    • java中@Configuration使用场景是什么
      这篇文章主要讲解了“java中@Configuration使用场景是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java中@Configuration使用场景是什么”吧!一、简单介绍@...
      99+
      2023-07-05
    • MySQL锁机制及应用场景是什么
      本文小编为大家详细介绍“MySQL锁机制及应用场景是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“MySQL锁机制及应用场景是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。锁的概述MySQL锁是操作My...
      99+
      2023-07-05
    • redis的五种数据类型及使用场景是什么
      redis 提供了五种数据类型,分别为:字符串:存储文本、json 数据、缓存、计数器;哈希:存储用户数据、会话信息、对象属性;列表:存储队列、时间线、排名、购物车;集合:存储标签、分类...
      99+
      2024-04-08
      键值对
    • Mysql中锁的使用场景是什么
      这篇文章主要讲解了“Mysql中锁的使用场景是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mysql中锁的使用场景是什么”吧!一、常见锁类型表级锁,锁...
      99+
      2024-04-02
    • Redis数据类型及应用场景是什么
      小编给大家分享一下Redis数据类型及应用场景是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1. string类型1-1 ...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作