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中的信号
  • 相关阅读:
    Asp.net弹出浏览器客户端确认对话框代码 Carlwave
    VS 2005 与SQL Server 2005整合优势在哪里?(from csdn.net) Carlwave
    如何让搜索引擎收录我的站点 Carlwave
    超强扩展性的DNNDotNetNuke模块功能分类列表(from 中国DNN) Carlwave
    DotNetNuke命名空间概述 Carlwave
    Most Popular Questions and Answers on ASP.NET Whidbey(from asp.net forums,write by ASP.NET Team) Carlwave
    火箭官方宣告麦蒂缺阵五周 季后赛前景蒙上阴影 Carlwave
    asp.net有效使用缓存(转) Carlwave
    《Business Rules Engine Overview》《业务规则引擎概述》write by Mark Kamoski Carlwave
    中国详细省市县自治区名称列表(含access数据库和sql2000备份数据库) Carlwave
  • 原文地址:https://www.cnblogs.com/zepc007/p/12051819.html
Copyright © 2011-2022 走看看