欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > 【后端】【Django】Django 信号(Signals)详解

【后端】【Django】Django 信号(Signals)详解

2025/4/1 7:27:42 来源:https://blog.csdn.net/qq_59344127/article/details/146553859  浏览:    关键词:【后端】【Django】Django 信号(Signals)详解

Django 信号(Signals)详解(循序渐进)

一、信号(Signal)概述

1. 什么是 Django 信号?

Django 信号(Signal) 是一种 观察者模式(Observer Pattern) 的实现,允许不同部分的代码在发生特定事件时进行通信,而不需要直接调用。
作用:当某个事件发生时,Django 会自动通知相关的信号处理函数,让它们执行相应的操作。

2. 信号的核心概念

  • 发送者(Sender):触发信号的对象(一般是 Django 模型)。
  • 信号(Signal):预定义的信号类型,例如 post_savepre_delete 等。
  • 接收器(Receiver):监听信号的函数,接收到信号后执行相应操作。
  • 连接(Connect):将信号与接收器绑定,使其在事件发生时被触发。

二、Django 内置信号

信号名称触发时机
pre_save调用 save() 之前
post_save调用 save() 之后
pre_delete调用 delete() 之前
post_delete调用 delete() 之后
m2m_changed多对多字段修改时
request_startedHTTP 请求开始时
request_finishedHTTP 请求结束时
got_request_exception视图抛出异常时
pre_migrate迁移前
post_migrate迁移后

三、信号的基本使用

1. 监听 post_save 信号

场景:User 被创建时,自动创建 Profile

(1)创建模型
from django.db import models
from django.contrib.auth.models import Userclass Profile(models.Model):user = models.OneToOneField(User, on_delete=models.CASCADE)bio = models.TextField(blank=True)
(2)在 signals.py 里定义信号
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):"""当用户创建时,自动创建 Profile"""if created:Profile.objects.create(user=instance)
  • @receiver(post_save, sender=User): 监听 User 模型的 post_save 事件。
  • created=True 时表示 新创建 的用户,此时自动创建 Profile
(3)注册信号

apps.py 里:

from django.apps import AppConfigclass MyAppConfig(AppConfig):default_auto_field = 'django.db.models.BigAutoField'name = 'myapp'def ready(self):import myapp.signals  # 确保信号被加载

四、信号的高级用法

1. 使用 pre_delete 软删除

场景:User 被删除时,不是真正删除,而是标记为已删除

(1)修改模型
class UserProfile(models.Model):user = models.OneToOneField(User, on_delete=models.CASCADE)is_deleted = models.BooleanField(default=False)  # 软删除标记
(2)监听 pre_delete
from django.db.models.signals import pre_delete@receiver(pre_delete, sender=User)
def soft_delete_user(sender, instance, **kwargs):"""用户删除时,不真正删除,而是标记 is_deleted"""instance.is_deleted = Trueinstance.save()
  • pre_delete 触发时,不直接删除,而是修改 is_deleted

2. 使用 m2m_changed 监听多对多关系

场景: 监听 BookAuthor 之间的多对多关系变更。

(1)创建模型
class Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=200)authors = models.ManyToManyField(Author)
(2)监听 m2m_changed
from django.db.models.signals import m2m_changed@receiver(m2m_changed, sender=Book.authors.through)
def book_authors_changed(sender, instance, action, **kwargs):"""当 Book 的 authors 关系发生变化时触发"""print(f"Action: {action}, Instance: {instance}")
  • m2m_changed 触发时,可以获取 action
    • pre_add:添加前
    • post_add:添加后
    • pre_remove:移除前
    • post_remove:移除后
    • pre_clear:清空前
    • post_clear:清空后

五、手动连接和断开信号

1. 手动连接信号

除了使用 @receiver,我们也可以手动绑定信号:

from django.db.models.signals import post_savedef my_signal_handler(sender, instance, **kwargs):print(f"{instance} 被保存了!")post_save.connect(my_signal_handler, sender=User)

优点

  • 可以在不同的地方注册信号,灵活性更高。

2. 断开信号

有时我们希望临时关闭某个信号:

post_save.disconnect(my_signal_handler, sender=User)

这样,post_save 信号就不会再触发 my_signal_handler


六、信号的调试和优化

1. 避免信号循环调用

如果 save() 方法中调用 save(),可能会导致 无限循环

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):if created:instance.profile = Profile.objects.create(user=instance)instance.save()  # ⚠️ 这里会导致递归调用

解决方案

  • save() 方法里 禁用信号
from django.db.models.signals import post_save@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):if created:post_save.disconnect(create_user_profile, sender=User)instance.profile = Profile.objects.create(user=instance)instance.save()post_save.connect(create_user_profile, sender=User)

2. 使用 weak=False 避免接收器被垃圾回收

默认情况下,@receiver 使用弱引用,如果接收器没有其他引用,可能会被回收:

post_save.connect(my_signal_handler, sender=User, weak=False)

七、总结

知识点说明
post_save在模型 save() 之后触发
pre_save在模型 save() 之前触发
post_deletedelete() 之后触发
pre_deletedelete() 之前触发
m2m_changed监听多对多关系变更
@receiver绑定信号的装饰器
connect()手动绑定信号
disconnect()手动解绑信号
避免循环调用save()断开信号 处理

Django 信号提供了强大的事件监听能力,可以帮助我们自动执行任务、减少代码耦合,但需要注意避免循环调用、调试信号、提高性能。🚀

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词