1-Django - 信号(signal)
before
首先,这里要模糊的说明一下,Django关于signals,也就是信号,有的也称为信号量,但它们都说的是Django的signals。而我要强调的是,如果提到信号量,我们应该想到的是多线程中的那把锁——信号量:
import time
import random
from threading import Semaphore, Thread, current_thread
def task():
with sm:
print('%s 正在上厕所' % current_thread().getName())
time.sleep(random.randint(1, 3))
if __name__ == '__main__':
sm = Semaphore(5)
for i in range(11):
t = Thread(target=task)
t.start()
OK,接下来说正事!
Django提供一种信号机制。其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) 。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。
通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。用于在框架执行操作时解耦。
在Django中,我们可以使用Django提供的内置信号,也可以自定义信号。
内置信号
Model signals
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发
Django提供了上述这么多的信号供我们使用,数据库相关信号,请求相关。
信号的使用
现在我的Django项目:
AT2/
├── AT2 # 项目目录
| └── __init__.py
├── web # 应用名
| └── models.py
└── my_signal.py # 自定义py文件
来了个问题:当对表做新增操作时,触发信号执行。
models.py
from django.db import models
class Tests(models.Model):
name = models.CharField(max_length=64, default='')
至于urls.py
就略过了,配个路由的事。
那么这里有两种方式触发信号的回调函数。
方式1
AT2\__init__.py
from django.db.models.signals import post_save
def my_callback(sender, **kwargs):
""" 回调函数 """
print(sender, kwargs)
post_save.connect(my_callback) # 信号触发回调函数
views.py
from django.shortcuts import render, redirect, HttpResponse
from web import models
def test(request):
models.Tests.objects.create(name='张开')
return HttpResponse("OK")
当请求test
接口的时候,orm执行了新增的操作,而同时AT2\__init__.py
中的回调函数同样会执行,打印的结果是:
<class 'web.models.Testss'> {'signal': <django.db.models.signals.ModelSignal object at 0x033862B0>, 'instance': <Tests: Tests object>, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}
可以看到有个字段'created': True
,说明是新增操作,我们就可以在这个函数中做些日志或别的操作了。
方式2
上面的调用实在是太low了,我们应该采用一个优雅的调用方式,就是采用装饰器方式。在AT2\__init__.py
,修改代码:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save)
def my_callback(sender, **kwargs):
""" 回调函数 """
print(sender, kwargs)
将回调函数用装饰器装饰一下即可。
需要注意的是,新增的时候,信号没啥问题,但是,要想在更新操作时触发信号执行,如果你这么写:
models.Tests.object.filter(pk=3).update(name="张开")
是不会触发上面设置的信号的,更新的操作要写成这样才可以:
obj = models.Testss.objects.filter(pk=3).first()
obj.name = '张开'
obj.save()
然后,通过回调函数的结果你可以发现:
<class 'web.models.Testss'> {'signal': <django.db.models.signals.ModelSignal object at 0x033862B0>, 'instance': <Testss: Testss object>, 'created': False, 'update_fields': None, 'raw': False, 'using': 'default'}
'created': False
了,那么这就是更新的提示,你看以通过这个参数来调整你的代码。
自定义信号
还是说一下如何自定义新号吧。
定义信号
在my_signal.py
中实现你的自定义信号:
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
注册信号
在AT2\__init__.py
中:
from django.dispatch import receiver
from my_signal import pizza_done
@receiver(pizza_done)
def my_callback(sender, **kwargs):
""" 回调函数 """
print(sender, kwargs)
触发信号
在views.py
:
from my_signal import pizza_done
from django.shortcuts import render, redirect, HttpResponse
from web import models
def test(request):
models.Tests.objects.create(name='张开')
pizza_done.send(sender=models.Testss.objects, toppings='abc')
return HttpResponse("OK")
当需要的时候,自己去触发信号的执行.......
that's all,see also:
https://www.cnblogs.com/wupeiqi/articles/5246483.html | https://blog.csdn.net/ponder008/article/details/6880400