Django(20):信号机制

目录

    • 信号的工作机制
    • 信号的应用场景
    • 两个简单例子
    • Django常用内置信号
    • 如何放置信号监听函数代码
    • 自定义信号
      • 第一步:自定义信号
      • 第二步:触发信号
      • 第三步:将监听函数与信号相关联

信号的工作机制

Django 框架包含了一个信号机制,它允许若干个发送者(sender)通知一组接收者(receiver)某些特定操作或事件(events)已经发生了, 接收者收到指令信号(signals)后再去执行特定的操作。

Django 中的信号工作机制依赖如下三个主要要素:

  • 发送者(sender):信号的发出方,可以是模型,也可以是视图。当某个操作发生时,发送者会发出信号。
  • 信号(signal):发送的信号本身。Django内置了许多信号,比如模型保存后发出的post_save信号。
  • 接收者(receiver):信号的接收者,其本质是一个简单的回调函数。将这个函数注册到信号上,当特定的事件发生时,发送者发送信号,回调函数就会被执行。

信号的应用场景

信号主要用于Django项目内不同事件的联动,实现程序的解耦。比如当模型A有变动时,模型B与模型C收到发出的信号后同步更新。又或当一个数据表数据有所改变时,监听这个信号的函数可以及时清除已失效的缓存。另外通知也是一个信号常用的场景,比如有人刚刚回复了你的贴子,可以通过信号进行推送。

注意:Django中信号监听函数不是异步执行,而是同步执行,所以需要异步执行耗时的任务时(比如发送邮件或写入文件),不建议使用Django自带的信号。

两个简单例子

假如我们有一个Profile模型,与User模型是一对一的关系。我们希望创建User对象实例时自动创建Profile对象实例,而更新User对象实例时不创建新的Profile对象实例。这时我们就可以自定义 create_user_profilesave_user_profile两个监听函数,同时监听sender (User模型)发出的post_save信号。由于post_save可同时用于模型的创建和更新,我们用if created这个判断来加以区别。

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiverclass Profile(models.Model):user = models.OneToOneField(User, on_delete=models.CASCADE)birth_date = models.DateField(null=True, blank=True)# 监听User模型创建    
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):if created:Profile.objects.create(user=instance)# 监听User模型更新  
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):instance.profile.save()

我们再来看一个使用信号清除缓存的例子。当模型A被更新或被删除时,会分别发出post_savepost_delete的信号,监听这两个信号的receivers函数会自动清除缓存里的A对象列表。

from django.core.cache import cache
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver@receiver(post_save, sender=ModelA)
def cache_post_save_handler(sender, **kwargs):cache.delete('cached_a_objects')@receiver(post_delete, sender=ModelA)
def cache_post_delete_handler(sender, **kwargs):cache.delete('cached_a_objects')

注意:有时为了防止信号多次发送,可以通过dispatch_uid给receiver函数提供唯一标识符。

@receiver(post_delete, sender=ModelA, dispatch_uid = "unique_identifier")

Django常用内置信号

前面例子我们仅仅使用了post_savepost_delete信号。Django还内置了其它常用信号:

  • pre_save & post_save: 在模型调用 save()方法之前或之后发送。
  • pre_init& post_init: 在模型调用_init_方法之前或之后发送。
  • pre_delete & post_delete: 在模型调用delete()方法或查询集调用delete() 方法之前或之后发送。
  • m2m_changed: 在模型多对多关系改变后发送。
  • request_started & request_finished: Django建立或关闭HTTP 请求时发送。

这些信号都非常有用。举个例子:使用pre_save信号可以在将用户的评论存入数据库前对其进行过滤,或则检测一个模型对象的字段是否发生了变更。

注意:监听pre_savepost_save信号的回调函数不能再调用save()方法,否则回出现死循环。另外Django的update方法不会发出pre_savepost_save的信号。

如何放置信号监听函数代码

在之前案例中,我们将Django信号的监听函数写在了models.py文件里。当一个app的与信号相关的自定义监听函数很多时,此时models.py代码将变得非常臃肿。一个更好的方式把所以自定义的信号监听函数集中放在app对应文件夹下的signals.py文件里,便于后期集中维护。

假如我们有个account的app,包含了User和Profile模型,我们首先需要在account文件夹下新建signals.py,如下所示:

# account/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import User, Profile@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):if created:Profile.objects.create(user=instance)@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):instance.profile.save()

接下来我们需要修改account文件下apps.py__init__.py,以导入创建的信号监听函数。

# apps.py
from django.apps import AppConfigclass AccountConfig(AppConfig):name = 'account'def ready(self):import account.signals# account/__init__.py中增加如下代码:
default_app_config = 'account.apps.AccountConfig'

自定义信号

Django的内置信号在大多数情况下能满足我们的项目需求,但有时我们还需要使用自定义的信号。在Django项目中使用自定义信号也比较简单,分三步即可完成。

第一步:自定义信号

每个自定义的信号,都是Signal类的实例。这里我们首先在app目录下新建一个signals.py文件,创建一个名为my_signal的信号,它包含有msg这个参数,这个参数在信号触发的时候需要传递。当监听函数收到这个信号时,会得到msg参数的值。

from django.dispatch import Signalmy_signal = Signal(providing_args=['msg'])

第二步:触发信号

视图中进行某个操作时可以使用send方法触发自定义的信号,并设定msg的值。

from . import signals
# Create your views here.def index(request):signals.my_signal.send(sender=None, msg='Hello world')return render(request, template_name='index.html')

第三步:将监听函数与信号相关联

from django.dispatch import Signal, Receivermy_signal = Signal(providing_args=['msg'])@receiver(my_signal)
def my_signal_callback(sender, **kwargs):print(kwargs['msg']) # 打印Hello world!

这样每当用户访问/index/视图时,Django都会发出my_signal的信号(包含msg这个参数)。回调函数收到这个信号后就会打印出msg的值来。

参考:https://pythondjango.cn/django/advanced/10-signala/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/85353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pcl--第十二节 2D和3D融合和手眼标定

2D&3D融合 概述 截止目前为止,我们学习了机器人学,学习了2D和3D视觉算法。我们也学习了2D相机(图像数据的来源)和3D相机(点云数据的来源)工作原理。 实际上,我们最终要做的,是一个手眼机器人系统。在这个系统里&#xff0c…

pytorch学习------常见的优化算法

优化算法 优化算法就是一种调整模型参数更新的策略,在深度学习和机器学习中,我们常常通过修改参数使得损失函数最小化或最大化。 优化算法介绍 1、梯度下降算法(batch gradient descent BGD) 每次迭代都需要把所有样本都送入&…

宝塔composer 安装laravel依赖出现的问题

环境宝塔、PHP版本8.0.2、laravel9 问题1:PHP Fatal error: Uncaught Error: Call to undefined function Composer\XdebugHandler\putenv() 办法:把PHP版本disable_functions这个中的putenv去掉,这个意思就是putenv被PHP对应的版本禁用了&…

深入了解队列数据结构:定义、特性和实际应用

文章目录 🍋引言🍋队列的定义🍋队列的实现🍋队列的应用🍋练习题🍋结语 🍋引言 队列(Queue)是计算机科学中一种重要的数据结构,它常用于各种应用程序中&#x…

RabbitMQ里的几个重要概念

RabbitMQ中的一些角色: publisher:生产者consumer:消费者exchange个:交换机,负责消息路由,接受生产者发送的消息,把消息发送到一个或多个队列里queue:队列,存储消息virt…

Hive【Hive(一)DDL】

前置准备 需要启动 Hadoop 集群,因为我们 Hive 是在 Hadoop 集群之上运行的。 从DataGrip 或者其他外部终端连接 Hive 需要先打开 Hive 的 metastore 进程和 hiveserver2 进程。metastore 和 hiveserver2 进程的启动过程比较慢,不要着急。 Hive DDL 数据…

基于SpringBoot的网上超市系统的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 用户功能实现 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计…

微软在Windows 11推出Copilot,将DALL-E 3集成在Bing!

美东时间9月21日,微软在美国纽约曼哈顿举办产品发布会,生成式AI成为重要主题之一。 微软表示,Copilot将于9月26日在Windows 11中推出;Microsoft 365 Copilot 将于11 月1日向企业客户全面推出;将OpenAI最新的文本生成图…

1201. 丑数 III -- 巧用二分搜索

1201. 丑数 III class Solution:"""巧用二分搜索1201. 丑数 IIIhttps://leetcode.cn/problems/ugly-number-iii/"""def nthUglyNumber(self, n: int, a: int, b: int, c: int) -> int:# 题目说本题结果在 [1, 2 * 10^9] 范围内left, right 1…

【货币单位换算】python实现-附ChatGPT解析

1.题目 题目描述: 记账本上记录了若干条多国货币金额,需要转换成人民币分 (fen),汇总后输出。 每行记录一条金额,金额带有货币单位,格式为数宁+单位, 可能是单独元,或者单独分,或者元与分的组合。 要求将这些货币全部换算成人民币分 (fen) 后进行汇总, 汇总结果仅保留整…

【论文阅读 08】Adaptive Anomaly Detection within Near-regular Milling Textures

2013年,太老了,先不看 比较老的一篇论文,近规则铣削纹理中的自适应异常检测 1 Abstract 在钢质量控制中的应用,我们提出了图像处理算法,用于无监督地检测隐藏在全局铣削模式内的异常。因此,我们考虑了基于…

GitHub Copilot Chat

9月21日,GitHub在官网宣布,所有个人开发者可以使用GitHub Copilot Chat。用户通过文本问答方式就能生成、检查、分析各种代码。 据悉,GitHub Copilot Chat是基于OpenAI的GPT-4模型打造而成,整体使用方法与ChatGPT类似。例如&…

TouchGFX之画布控件

TouchGFX的画布控件,在使用相对较小的存储空间的同时保持高性能,可提供平滑、抗锯齿效果良好的几何图形绘制。 TouchGFX 设计器中可用的画布控件: LineCircleShapeLine Progress圆形进度条 存储空间分配和使用​ 为了生成反锯齿效果良好的…

华为云云耀云服务器L实例评测 | minikube部署和使用

### 1 安装Docker 按照官网[Docker docs](https://docs.docker.com/engine/install/centos/)指引安装: shell yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install docker-ce docker-…

[C++随笔录] vector模拟实现

vector模拟实现 基本结构天选之子构造拷贝构造析构operator 空间reserveresizesize && capacity 增insertpush_back 删erasepop_back 查 && 改swapoperator[] 源码 基本结构 // 可以是不同类型, 用类模板 template <class T> class vector { public:// 源…

将来已来-SoftwareDemo软件测试种子的埋下去-第二次重大情绪点的触及到

岗位需要&#xff0c;一头扎进了软件测试的方向里面去了。过去下过无数次决心&#xff0c;做成一个事情的方向&#xff0c;想不到换成了软件测试的了。不知道这次&#xff0c;会不会持续下去。 这是进入软件开发行业以来的一种重大变革&#xff0c;犹如泽火革卦象&#xff1b; …

git和github的入门操作

之前因为工作中用的都是SVN版本控制工具&#xff0c;没接触过git和github&#xff0c;现在开始深入自学Django框架技术后&#xff0c;看到官网推荐使用git&#xff0c;然后这两天网上查阅了很多文章教程&#xff0c;学到入门操作需要学习的点&#xff0c;太多的知识点要后面慢慢…

PHP常见的SQL防注入方法

利用Mysqli和PDO 产生原因主要就是一些数据没有经过严格的验证&#xff0c;然后直接拼接 SQL 去查询。导致产生漏洞&#xff0c;比如&#xff1a; $id $_GET[id]; $sql "SELECT name FROM users WHERE id $id";因为没有对 $_GET[‘id’] 做数据类型验证&#xf…

感知器算法

感知器是一种简单的机器学习算法&#xff0c;用于二元分类问题&#xff08;即将数据分为两个类别&#xff09;。它是人工神经网络的早期形式&#xff0c;由Frank Rosenblatt在1957年提出。感知器的主要思想是通过学习权重来分隔不同类别的数据点。 以下是感知器算法的基本步骤&…