本文最先发表于我的博客 Pylixm'wiki-django signal使用总结html
最近在已经开发好的项目上加功能,想到了django的signal,整理记录以下备查。python
官方文档描述以下:shell
Django includes a “signal dispatcher” which helps allow decoupled applications get notified when actions occur elsewhere in the framework.In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events.django
Django内部包含了一位“信号调度员”:当某事件在框架内发生时,它能够通知到咱们的应用程序。 简而言之,当event(事件)发生时,signals(信号)容许若干 senders(寄件人)通知一组 receivers(接收者)。这在咱们多个独立的应用代码对同一事件的发生都感兴趣时,特别有用。app
我的理解,django的signal可理解为django内部的钩子,当一个事件发生时,其余程序可对其做出相关反应,可经过signal来回调定义好的处理函数(receivers),从而更大程度的解耦咱们的系统。框架
通知是signal最经常使用的场景之一。例如,在论坛中,在帖子获得回复时,通知楼主。从技术上来说,咱们能够将通知逻辑放在回复保存时,可是这并非一个好的处理方式,这样会时程序耦合度增大,不利于系统的后期扩展维护。若是咱们在回复保存时,只发一个简单的信号,外部的通知逻辑拿到信号后,再发送通知,这样回复的逻辑和通知的逻辑作到了分开,后期维护扩展都比较容易。函数
信号的另外一个列子即是事件完成后,作一系列的初始化工做。post
如下状况不要使用signal:ui
signal与一个model紧密相关, 并能移到该model的save()时spa
signal能使用model manager代替时
signal与一个view紧密相关, 并能移到该view中时
如下状况可使用signal:
signal的receiver须要同时修改对多个model时
将多个app的相同signal引到同一receiver中处理时
在某一model保存以后将cache清除时
没法使用其余方法, 但须要一个被调函数来处理某些问题时
django 的 signal 使用可分为2个模块:
signal :signal定义及触发事件
receiver : signal 接受函数
django 内部有些定义好的signal供咱们使用:
模型相关:
pre_save 对象save前触发
post_save 对象save后触发
pre_delete 对象delete前触发
post_delete 对象delete后触发
m2m_changed ManyToManyField 字段更新后触发
请求相关:
request_started 一个request请求前触发
request_finished request请求后触发
针对django自带的signal,咱们只须要编写receiver 便可,使用以下。
myapp/signals/handlers.py
from django.dispatch import receiver from django.core.signals import request_finished ## decorators 方式绑定 @receiver(request_finished, dispatch_uid="request_finished") def my_signal_handler(sender, **kwargs): print("Request finished!================================") # 普通绑定方式 def my_signal_handler(sender, **kwargs): print("Request finished!================================") request_finished.connect(my_signal_handler) ##################################################### # 针对model 的signal from django.dispatch import receiver from django.db.models.signals import post_save from polls.models import MyModel @receiver(post_save, sender=MyModel, dispatch_uid="mymodel_post_save") def my_model_handler(sender, **kwargs): print('Saved: {}'.format(kwargs['instance'].__dict__))
dispatch_uid 确保此receiver 只调用一次
myapp/__init__py
default_app_config = 'myapp.apps.MySendingAppConfig'
myapp/apps.py
from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'myapp' def ready(self): # signals are imported, so that they are defined and can be used import myapp.signals.handlers
到此,当系统受到request 请求完成后,便会执行receiver。
其余内建的signal,参考官方文档:
https://docs.djangoproject.com/en/1.9/topics/signals/
自定义signal,须要咱们编写 signal和 receiver 。
myapp.signals.signals.py
import django.dispatch my_signal = django.dispatch.Signal(providing_args=["my_signal_arg1", "my_signal_arg_2"])
myapp/__init__py
default_app_config = 'myapp.apps.MySendingAppConfig'
myapp/apps.py
from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'myapp' def ready(self): # signals are imported, so that they are defined and can be used import myapp.signals.handlers
myapp/views.py
from .signals.signals import my_signal my_signal.send(sender="some function or class", my_signal_arg1="something", my_signal_arg_2="something else"])
自定义的signal,django已经为咱们编写了此处的事件监听。
myapp/signals/handlers.py
from django.dispatch import receiver from myapp.signals.signals import my_signal @receiver(my_signal, dispatch_uid="my_signal_receiver") def my_signal_handler(sender, **kwargs): print('my_signal received')
此时,咱们自定义的signal 便开发完成了。
django signal 的处理是同步的,勿用于处理大批量任务。
django signal 对程序的解耦、代码的复用及维护性有很大的帮助。
以上为我的观点,若有疑问欢迎交流。
http://sabinemaennel.ch/django/signals-in-django/
https://docs.djangoproject.com/en/1.10/topics/signals/
http://www.weiguda.com/blog/38/
http://www.python88.com/topic/151