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

posted @ 2019-10-21 21:05  听雨危楼  阅读(727)  评论(0编辑  收藏  举报