zoukankan      html  css  js  c++  java
  • Django信号机制相关解释与示例

    Django 信号#

    django自带一套信号机制来帮助我们在框架的不同位置之间传递信息。也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)发送给一组接受者(receivers)。

    也就是观察者模式,又叫发布-订阅(Publish/Subscribe)。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

    信号系统包含以下三要素:

    • 发送者-信号的发出方
    • 信号-信号本身
    • 接收者-信号的接受者

    Django内置的信号

    1. Model signals
      1. django.db.models.signals.pre_save 在某个Model保存之前调用
      2. django.db.models.signals.post_save 在某个Model保存之后调用
      3. django.db.models.signals.pre_delete 在某个Model删除之前调用
      4. django.db.models.signals.post_delete 在某个Model删除之后调用
      5. django.db.models.signals.pre_init 在某个Model实例化__init__()方法执行前调用
      6. django.db.models.signals.post_init 在某个Model实例化__init__()方法执行后调用
      7. django.core.signals.m2m_changed 在某个Model实例上更改了ManyToManyField时发送
    2. Management signals
      1. django.core.signals.pre_migrate 在某个app更新(migrate)前发送
      2. django.core.signals.post_migrate 在某个app更新(migrate)后发送
    3. Request/response signals
      1. django.core.signals.request_started 在建立Http请求时发送
      2. django.core.signals.request_finished 在关闭Http请求时发送
      3. django.core.signals.got_request_exception 在请求异常时发送
    4. Test signals
      1. setting_changed 使用test测试修改配置文件时,自动触发
      2. template_rendered 使用test测试渲染模板时,自动触发
    5. Database Wrappers
      1. connection_created 创建数据库连接时,自动触发

    对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数

    Copy
    def my_callback(sender, **kwargs):
        print("Request finished!")
    
    # 方法一:
    from django.core.signals import request_finished
    
    request_finished.connect(my_callback)
    
    # 方法二:
    from django.core.signals import request_finished
    from django.dispatch import receiver
    
    @receiver(request_finished)
    def my_callback(sender, **kwargs):
        print("Request finished!")
    
    

    监听信号#

    要接收信号,请使用Signal.connect()方法注册一个接收器。当信号发送后,会调用这个接收器。

    方法原型:

    Copy
    Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)[source]

    参数:

    Copy
    receiver :当前信号连接的回调函数,也就是处理信号的函数。 
    sender :指定从哪个发送方接收信号。 
    weak : 是否弱引用
    dispatch_uid :信号接收器的唯一标识符,以防信号多次发送。

    下面以如何接收每次HTTP请求结束后发送的信号为例,连接到Django内置的现成的request_finished信号。

    1. 编写接收器#

    接收器其实就是一个Python函数或者方法:

    Copy
    def my_callback(sender, **kwargs):
        print("Request finished!")

    请注意,所有的接收器都必须接收一个sender参数和一个**kwargs通配符参数。

    2. 连接接收器#

    有两种方法可以连接接收器,一种是下面的手动方式:

    Copy
    from django.core.signals import request_finished
    
    request_finished.connect(my_callback)

    另一种是使用receiver()装饰器:

    Copy
    from django.core.signals import request_finished
    from django.dispatch import receiver
    
    @receiver(request_finished)
    def my_callback(sender, **kwargs):
        print("Request finished!")

    3. 接收特定发送者的信号#

    一个信号接收器,通常不需要接收所有的信号,只需要接收特定发送者发来的信号,所以需要在sender参数中,指定发送方。下面的例子,只接收MyModel模型的实例保存前的信号。

    Copy
    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    from myapp.models import MyModel
    
    
    @receiver(pre_save, sender=MyModel)
    def my_handler(sender, **kwargs):
        pass

    4. 防止重复信号#

    为了防止重复信号,可以设置dispatch_uid参数来标识你的接收器,标识符通常是一个字符串,如下所示:

    Copy
    from django.core.signals import request_finished
    
    request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

    最后的结果是,对于每个唯一的dispatch_uid值,你的接收器都只绑定到信号一次。

    自定义信号#

    除了Django为我们提供的内置信号(比如前面列举的那些),很多时候,我们需要自己定义信号。

    类原型:class Signal(providing_args=list)[source]

    所有的信号都是django.dispatch.Signal的实例。providing_args参数是一个列表,由信号将提供给监听者的参数的名称组成。可以在任何时候修改providing_args参数列表。

    下面定义了一个新信号:

    Copy
    import django.dispatch
    
    pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

    上面的例子定义了pizza_done信号,它向接受者提供size和toppings 参数。

    发送信号#

    Django中有两种方法用于发送信号。

    Copy
    Signal.send(sender, **kwargs)[source]
    
    
    Signal.send_robust(sender,** kwargs)[source] 

    必须提供sender参数(大部分情况下是一个类名),并且可以提供任意数量的其他关键字参数。

    例如,这样来发送前面的pizza_done信号:

    Copy
    import django.dispatch
    
    pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
    
    class PizzaStore(object):
        ...
    
        def send_pizza(self, toppings, size):
            pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
            ...

    send()send_robust()返回一个元组对的列表[(receiver, response), ... ],表示接收器和响应值二元元组的列表。

    断开信号#

    方法:

    Copy
    Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)[source]

    Signal.disconnect()用来断开信号的接收器。和Signal.connect()中的参数相同。如果接收器成功断开,返回True,否则返回False。

    信号使用实例#

    信号可能不太好理解,下面我在Django内编写一个例子示范一下:

    urls.py

    Copy
    from django.conf.urls import url
    from django.contrib import admin
    from signal_demo import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^signal/', views.signal_view),
    ]
    

    views.py

    Copy
    from django.dispatch import receiver, Signal
    from django.shortcuts import HttpResponse
    import time
    
    # 自定义信号
    my_signal = Signal(providing_args=['path', 'time'])
    
    
    def signal_view(request):
        # 接受到请求,发送信号
        res = my_signal.send(signal_view, path=request.path, time=time.strftime("%Y-%m-%d %H:%M:%S"))
        # 返回一个元组对的列表`[(receiver, response), ... ],表示接收器和响应值二元元组的列表
        print(res)
        return HttpResponse('200,ok')
    
    
    @receiver(my_signal, sender=signal_view)
    def my_callback(sender, **kwargs):
        print("我在%s时间收到来自%s的信号,请求url为%s" % (kwargs['time'], sender, kwargs["path"]))
        return 'ok'
    

    启动Django服务

    访问 http://127.0.0.1:8000/signal/

    console打印

    Copy
    [XX] "GET /signal/ HTTP/1.1" 200 6
    我在XXX时间收到来自<function signal_view at 0x000001FA31DFCD08>的信号,请求url为/signal/
    [(<function my_callback at 0x000001FA31E20378>, 'ok')]
    

    Django 信号原理,源码分析#

    观察者模式,又叫发布-订阅(Publish/Subscribe)。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

    DJango实现信号的原理是: 回调函数,串行执行

    1. 发送者 发送 信号
    2. 信号 处理,回调 接收者
    3. 接收者处理
    4. 信号拿到接收者的返回值
    5. 发送者拿到信号的返回值(就是接收者的返回值)

    参考#

    1. 官方文档
    2. Django的信号机制
    3. 信号 signal
    4. Django中的信号
  • 相关阅读:
    【Spring Security学习之一】Spring Security入门
    【OAuth 2.0学习之一】OAuth 2.0入门
    【JWT学习之二】JWT实现单点登录
    【JWT学习之一】JWT入门
    【CAS学习之三】CAS客户端验证
    【CAS学习之二】部署CAS服务端
    【CAS学习之一】CAS入门
    ES 聚合分类(text字段)语句报错
    LeNet网络在fashion MNIST数据集上的实现
    动手深度学习 pytorch
  • 原文地址:https://www.cnblogs.com/zepc007/p/12051819.html
Copyright © 2011-2022 走看看