Django信号的基本使用
目录
介绍
信号在 Django 中的作用是允许开发者在特定事件发生时执行自定义逻辑。通过连接信号到相应的处理函数,开发者可以轻松地在应用程序的不同部分添加额外的处理逻辑,而无需修改原始的代码
信号的作用包括但不限于:
- 解耦合:使用信号可以将特定功能的实现从原始的业务逻辑中解耦出来,提高了代码的模块化程度,降低了代码的耦合性
- 扩展性:允许第三方应用或插件通过连接信号的方式来扩展应用程序的功能,而无需修改应用程序的源代码
- 事件驱动:使得应用程序变得事件驱动,即当特定事件发生时,可以触发相关的处理逻辑,增强了应用程序的灵活性
- 可重用性:通过连接信号,可以编写通用的信号处理函数,使得这些处理逻辑能够被多个事件重用,提高了代码的可重用性
常用内置信号
信号类别 | 信号名称 | 触发时机 | 发送者 | 参数 |
---|---|---|---|---|
模型层信号 | pre_save | 模型实例保存前 | 模型的class | sender (模型类)、instance (模型实例)、raw (是否为原始查询)、using (使用的数据库别名)、update_fields (仅当更新特定字段时提供) |
post_save | 模型实例保存后 | 模型的class | 同上,另加created (是否是新创建的实例) | |
pre_delete | 模型实例删除前 | 模型的class | sender (模型类)、instance (模型实例)、using (使用的数据库别名) | |
post_delete | 模型实例删除后 | 模型的class | 同上 | |
m2m_changed | 多对多关系变更时 | 模型的class | sender (模型类)、action (操作类型,如"add" , "remove" , "clear" )、reverse (是否为反向关系)、model (关联模型)、pk_set (变更的PK集合,对于"add" 和"remove" )、instance (触发变更的实例) | |
pre_init | 模型实例初始化前 | 模型的class | sender (模型类)、args (传递给__init__ 方法的参数)、kwargs (传递给__init__ 方法的关键字参数) | |
post_init | 模型实例初始化后 | 模型的class | 同上 | |
管理信号 | pre_migrate | 在执行migrate命令前 | Django内部信号系统 | 无特定参数,但可能包含Django内部使用的信息 |
post_migrate | 在执行migrate命令后 | Django内部信号系统 | sender :当前正在处理的应用配置(AppConfig)的实例 、app_config :同上(在旧版Django中可能是app )、verbosity :命令行输出信息的详细级别(通常是整数) ,interactive :是否是交互式运行(例如,在shell中,而不是通过脚本)、using :用于迁移的数据库别名(默认是default )、 apps :一个包含所有已加载应用的字典 | |
请求/响应信号 | request_started | 在请求到来前 | Django内部信号系统 | 无特定参数,但可能包含与请求相关的内部信息 |
request_finished | 在请求结束后 | Django内部信号系统 | sender :None (通常不使用) 、request :当前请求的HttpRequest对象 | |
got_request_exception | 在请求异常后 | Django内部信号系统 | sender :None (通常不使用) 、request :当前请求的HttpRequest对象、 exception :在请求处理过程中引发的异常对象 | |
测试信号 | setting_changed | 在使用test测试修改配置文件时 | django.test.signals.setting_changed | sender :django.conf.Settings 的实例、 setting :发生更改的设置的名称(字符串)、 value :设置的新值、 enter :布尔值,表示是否正在进入上下文(例如,使用override_settings 装饰器时) |
template_rendered | 在使用test测试渲染模板时 | django.test.signals.template_rendered | sender :django.template.backends.base.Template 的实例 、template :用于渲染的模板对象 、context :模板渲染时使用的Context对象 | |
数据库信号 | connection_created | 在创建数据库连接时 | 数据库后端(如django.db.backends.postgresql.base.DatabaseWrapper ) | sender :数据库连接的实例(例如,PostgreSQL后端的DatabaseWrapper ) |
使用演示
假设现在有一个User表,需求:在User实例被创建时(添加用户后)控制台打印该用户邮箱
1.创建用户表
从AbstractUser
继承,这是 Django 内置的代表用户的模型,用户名就是username
不需要我们重写,额外扩写了email
字段
import json
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
email = models.EmailField(verbose_name='邮箱', help_text='邮箱', null=True, blank=True)
class Meta:
db_table = 'user'
verbose_name = '用户'
verbose_name_plural = verbose_name
def __str__(self):
return self.username
2.创建信号接收器(接受函数)
在需要使用信号的app文件下新建signals.py
,并新建信号接收函数my_handler
sender
:模型类instance
:模型实例created
:是否是新建的实例
# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import User
@receiver(post_save, sender=User)
def my_handler(sender, instance, created, **kwargs):
if created:
print(f"用户{instance.username}已经被创建, 邮箱{instance.email}:, model来源:{sender.__name__}")
else:
print(f"{instance.username} 已更新新邮箱: {instance.email}")
3.将信号添加至应用配置
在 Django 启动时,会执行 ready()
方法,并且会导入并注册用户信号处理函数模块。
# apps.py
from django.apps import AppConfig
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'
def ready(self):
import user.signals # 在这里导入信号处理函数模块,user是app的名称
4.测试
对接口进行添加用户操作
{
"username":"tianqing",
"password":"2e2e2e2e2e",
"email":"azure@qq.com",
}
控制台输出:
现在对用户进行更新
{
"username":"tianqing",
"password":"2e2e2e2e2e",
"email":"azure1@qq.com",
}
控制台输出:
自定义信号
其实自定义信号只比内置信号多了两步:定义信号,.send
发送信号
定义信号一般也在signals.py
中执行
在任何想要使用信号的地方直接.send
发送信号
1.定义信号
# myapp/signals.py
from django.dispatch import Signal
# 定义一个名为 my_custom_signal 的信号,允许的参数sender和message
my_custom_signal = Signal(providing_args=["sender", "message"])
2.发送信号
# myapp/views.py
from .signals import my_custom_signal
def some_view(request):
# ... 执行一些操作 ...
# 发送信号,带上 sender 和 message 参数
my_custom_signal.send(sender=self.__class__, message="这是一条自定义信号")
# ... 其他操作 ...
3.创建信号接收器
# myapp/signals.py
from django.dispatch import receiver
from .models import MyModel
@receiver(my_custom_signal)
def my_signal_receiver(sender, **kwargs):
message = kwargs.get('message')
print(f"信号来源:{sender}: {message}")
# 你也可以在这里进行其他操作,比如保存到数据库、发送邮件等
# 例如,你可以创建一个 MyModel 的实例来保存信号的信息
MyModel.objects.create(content=message)
4.将信号添加至应用配置
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
import myapp.signals # 导入 signals 模块,以触发信号接收函数的连接