深入理解Django的信号机制
Django的信号
Django的信号机制不同于Linux的信号机制,Django 中的信号用于在框架执行操作时解耦。当某些动作发生的时候,系统会根据信号定义的函数执行相应的操作
Django的信号主要包含以下三个要素:
- 发送者(sender):信号的发出方。
- 信号(signal):发送的信号本身。
- 接收者(receiver):信号的接收者。
其中接受者就是回调函数,会把这个函数注册到信号之上。当特定事件发生之后,发送者发送信号,然后执行回调函数。
Django信号的使用
查看Django Signal的源码,看到Django的信号存在以下方法
除了上面的几个方法,还有几个属性
- lock
- recievers
- sender_receivers_cache
- use_caching
根据第一趴介绍知道,要使用Django的信号,需要满足三要素(发送者、接受者、和信号)
Django通过
connect()
函数监听
信号,接受发送者发送的信号,然后执行接受者(回调函数)
Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)
其中
- recievers 是接受者,本质就是一个回调函数
- sender 是发送信号的主体,如果connect连接的时候,sender 是None(默认也是None)代表该信号接受所有发送者发送的该信号;否则只接受具体的发送者(一个Python对象,比如Django的 Model对象)
- weak – Django 默认将信号处理程序存储为弱引用。因此,如果你的接收器是本地函数,则可能会对其进行垃圾回收。要防止这种情况发生,当你要调用 connect() 方法时请传入 weak=False。
- dispatch_uid 在可能发送重复信号的情况下,信号接收器的唯一标识符。
具体使用方式
1、需要定义一个回调函数
def my_callback(sender, **kwargs):
print("Request finished!")
2、把回调函数
注册到对应的信号
from django.core.signals import request_finished
request_finished.connect(my_callback)
注意这里没有指定sender,那么就是接受任意发送者哦
或者更简单的方式是使用 receiver
函数
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")
或者指定具体的发送者
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished, sender="MyTagModel")
def my_callback(sender, **kwargs):
print("Request finished!")
==> 划重点
一般我们会把 回调函数
和 信号注册
放到一个应用的目录下的 signals.py 文件中去
然后在该应用的 apps.py 中应用
from django.apps import AppConfig
from django.core.signals import request_finished
class MyAppConfig(AppConfig):
...
def ready(self):
# Implicitly connect signal handlers decorated with @receiver.
from . import signals
# Explicitly connect a signal handler.
request_finished.connect(signals.my_callback)
这样只要改应用安装在 INSTALLED_APPS
中去,那么Django就能识别到具体的信号(包括自定义的信号)以及进行信号的处理(因为已经自动通过 connect进行监听 )
为啥会自动监听呢,当然是 Django的 AppConfig
下的 ready() 函数的作用
自定义信号
首先有个核心点需要明确
所有的信号都是
django.dispatch.Signal
的实例。
比如这里新增一个发送邮件的信号,每次新增Post之后,发送邮件给相关订阅的人
# demoapp/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Post
@receiver(post_save, sender=Post)
def send_mail(sender, instance, created, **kwargs):
if created:
print(f"current instance {instance}")
print("Try to send mail to subscriber")
然后把信号导入到 appConfig 的ready() 函数中去
# demoapp/apps.py
from django.apps import AppConfig
class DemoappConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'demoapp'
def ready(self):
import demoapp.signals
然后我们在admin注册Post之后,新增Post,在命令行日志中就能看到
current instance DemoPost First One
Try to send mail to subscriber
[02/Feb/2023 13:47:29] "POST /admin/demoapp/post/add/ HTTP/1.1" 302 0
还有另外一个 主动发送信号
的方式
1、先定义回调函数 callback_func
2、定义一个信号 mail_send_signal = Signal()
3、回调函数注册到信号 mail_send_signal.connect(callback_func)
3、主动发送信号 mail_send_signal.send(sender=xxx, **kwargs)
具体的代码实现,可以手动尝试哦,实践出真知嘛~
扩展:查看Django信号的接受者
Django内置信号的reciever查看
(kfzops) [ 23-02-02 16:04 ] [ colinspace.com ] python manage.py shell
Python 3.9.6 (default, Jul 16 2021, 13:41:17)
[Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.db.models.signals import post_migrate
>>> post_migrate.receivers
[(('django.contrib.auth.management.create_permissions', 4304618416), <weakref at 0x10232b310; to 'function' at 0x10231d1f0 (create_permissions)>), ((4331786592, 4304618416), <weakref at 0x102581e00; to 'function' at 0x10231d160 (create_contenttypes)>)]
扩展:Django内置信号
Django内置了很多有用的信号,大概有以下几类,可以作为了解。
模型相关的信号
- pre_init
- post_init
- pre_save
- post_save
- pre_delete
- post_delete
- m2m_changed
- class_prepared
其中
1、pre_init/post_init 分别会在模型的__init__()
方法调用 之前/之后发出
2、pre_save/post_save 分别会在模型的save()
方法调用 之前/之后发出
3、pre_delete/post_delete 分别会在模型的delete()
方法调用 之前/之后发出
4、m2m_changed 严格意义上来说是由ManyToManyField
字段发生变化的时候发出的
5、class_prepared 比较特殊一般不建议用
django-admin 发出的信号,确切的说是 Django admin在执行 python manage.py migrate的时候发出的信号
- pre_migrete
- post_migrate
顾名思义,不做过多解释
请求响应信号,也就是Django 发起request和响应response的信号
- request_started
- request_finished
- get_request_exception
另外还有几个特殊的信号
1、setting_changed 只有当运行测试用例的时候发出
2、template_render 当测试系统渲染模板的时候发出
3、connect_created 当数据库连接启动的时候,数据库管理器发出
参考文档
1、 https://docs.djangoproject.com/zh-hans/4.1/topics/signals/
到此这篇关于深入理解Django的信号机制的文章就介绍到这了,更多相关Django 信号机制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341