参考:https://docs.djangoproject.com/en/1.11/ref/signals/

1、Model signals

  django.db.models.signales 作用于django的model操作上的一系列信号

  1)pre_init()

    django.db.models.signals.pre_init

    当模型实例化时调用,在__init__()之前执行

    三个参数:

      pre_init(sender, args, kwargs):

        sender:创建实例的模型类

        args:参数列表

        kwargs:通过字典形式传递的参数

  2)post_init()

    django.db.models.signals.post_init

    它和pre_init可以说是一对,也是作用于模型实例化时,它是在__init__()之后被执行

    它有两个参数:

      post_init(sender, instance)

        sender:同上,创建实例的模型类

        instance:创建的实例

  3)pre_save()

    django.db.models.signals.pre_save

    在model执行save方法前被调用

    5个参数:

      pre_save(sender,instance,raw,using,update_fields)

        sender:model类

        instance:保存的实例

        raw:一个Boolean类型,如果model被全部保存则为True

        using:使用的数据库别名

        update_fields:传递的待更新的字段集合,如果没有传递,则为None

  4)post_save()

    djang.db.models.post_save

    在model执行完save方法后被调用

    6个参数

      post_save(sender,instance,created,raw,using,update_fields)

        sender:model class

        instance:被保存的model实例

        created:Boolean值,如果创建了一个新的记录则为True

        raw:Boolean值,如果model被全部保存则为True

        using:使用的数据库别名

        update_fields:传递的待更新的字段集合,如果没有传递,则为None

  5)pre_delete()

    django.db.models.signals.pre_delete

    在执行model的delete()或者queryset的delete()方法前调用

    pre_delete(sender,instance,using)

      sender:model class

      instance:被删除的实例

      using:使用的数据库别名

  6)post_delete()

    django.db.models.signals.post_delete

    在执行model的delete()或者queryset的delete()方法后调用

    post_delete(sender, instance,using)

      sender:model class

      instance:被删除的实例,注意:此时,该实例已经被删除了,数据库中不再有这条记录,所以在使用这个实例的时候要格外注意

      using:被使用的数据库别名

  7)m2m_changed()

    django.db.models.signals.m2m_changed

    当一个model的ManyToManyField发生改变的时候被发送,严格的说,这并不是一个模型信号,因为它是被ManyToManyField发送的,但是因为它也实现了pre_save/post_save和pre_delete/post_delete,所以也在model signals中包含了。

    参数:

      sender:描述ManyToManyField的中间模型类,这个中间模型类会在一个many-to-many字段被定义时自动被创建。我们可以通过使用many-to-many字段的through属性来访问它

      instance:被更新的多对多关系的实例。它可以是上面的sender,也可以是ManyToManyField的关系类。

      action:指明作用于关系更新类型的字符串,它可以是以下几种情况:

        "pre_add"/"post_add":在向关系发送一个或多个对象前 / 后发送

        "pre_remove/post_remove":从关系中删除一个或多个对象前 / 后发送

        "pre_clear/post_clear":在关系解除之前 / 之后发送

      reverse:正在修改的是正向关系或者反向关系,正向False,反向为True

      model:被添加、删除或清除的对象的类

      pk_set:对于add/remove等,pk_set是一个从关系中添加或删除的对象的主键 的集合, 对于clear,pk_set为None

    举例说明:

      两个实例,且关系如下:

        class Topping(models.Model):

          pass

        class Pizza(models.Model):

          toppings = ManyToManyFields(Topping)

      我们像这样连接一个处理器

        from django.db.models.signals import m2m_changed

        def toppings_changed(sender, **kwargs):

          pass

        m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)

      然后我们对上面的类做如下操作

        p = Pizza.objects.create(...)

        t = Topping.objects.create(...)

        p.toppings.add(t)

      这样,对应的上面的参数分别如下:

        sender:描述ManyToManyField的中间类,即Pizza.toppings.through

        instance:被更新的多对多关系的实例,即P(本例中,Pizza对应被更改)

        action:先是"pre_add",然后执行上面的操作add(),最后再调用了"post_add"

        reverse:本例中,Pizza包含了ManyToManyField topping,然后调用P.toppings.add(),所以这是正向更新,故reverse为False

        model:被添加删除或清除的类,本例中 Topping 被添加到Pizza

        pk_set:{t.id}

      我们再做下面的操作:

        t.pizza_set.remove(p)

      这样,对应的参数为:

        sender:同上

        instance:t(本例中,Topping实例被更改)

        action:先是"pre_remove",然后执行上面的remove,再执行"post_remove"

        reverse:True,本例中,是反向操作

        model:p

        pk_set:{p.id}

  8)class_prepared

    django.db.models.signals.class_prepared

    当模型类准备好时发送,即当模型被创建并注册到Django的模型系统中时。

    这个信号通常是在Django内部使用,一般不会被第三方应用使用。

2、Request/response signals

  在处理请求时发出的信号

  1)request_started()

    django.core.signals.request_started

    在Django开始处理HTTP请求时发送。

    request_started(sender,environ)

  2)request_finished()

    django.core.signals.request_finished

    在Django处理完HTTP请求时发送

  3)got_request_exception()

    django.core.signals.got_request_exception

    在处理HTTP请求过程中遇到错误时发送。

3、使用信号

  1)监听信号

    即想要接收信号,可以使用Signals.connect()方法注册一个接收器函数,当信号被发送时接收器函数被调用。

    Signals.connect(receiver,sender=None,weak=True,dispatch_uid = None)  

      receiver:将连接到此信号的回调函数

      sender:指定要接收信号的特定发送方

      weak:Django默认将信号处理程序存储为弱引用。因此,如果我们的接收器是一个弱引用,那么它有可能会被垃圾回收机制给回收掉,为了防止这种情况,

          我们在调用信号的connect()方法时,传递weak=False。

      dispatch_uid:给信号接收方定义的唯一标识,以防可能会有重复信号发送。

  接下来以HTTP请求中的request_finished信号为例:

  2)定义接收函数

    def my_func_callback(sender, **kwargs):

      print("request_finished")

    如上,所有的接收函数必须要包含sender和关键字参数两个参数。

  3)连接接收函数

    有两种方法和将接收器和信号连接起来,我们可以选择手动的连接线路,如下:

      from django.core.signals import request_finished

      request_finished.connect(my_func_callback)

    我们还可以选择通过装饰器来连接信号和接收器

      from django.dispatch import receiver

      from django.core.signals import request_finished

      @receiver(request_finished)

      def my_func_callback(sender, **kwargs):

        pass

    注意:在实践中,信号处理程序通常定义在与他们相关的应用程序的信号子模块中,信号接收器连接在我们的应用程序配置类的ready()方法中。如果使用装饰器方式,我们只需要在reader()中导入signals子模块即可。

       值得一提的是,在测试过程中,我们的ready()函数可能不止一次被执行,因此我们要保护我们的信号不要被复制。

  4)连接到特定发送者发送的信号

    在很多情况下,我们的信号会被多次发送,但是实际上我们只对这些信号的某个子集感兴趣,例如前面收的pre_save()信号

    这时候,我们可以注册只接收特定发送者发送的信号。如下,我们可以指定我们需要接收的某个模型发送的信号

    from djang.db.models.signals import pre_save

    from django.dispatch import receiver

    from .model import MyModel

    @receiver(pre_save, sender=MyModel)

    def my_receiver(sender, **kwargs):

      pass

    这样,我们的my_receiver()函数将只有在MyModel被保存时被调用。

  5)防止重复的信号:

    在某些情况下,连接接收器到信号的代码可能会运行多次,这可能会导致我们的接收器函数注册不止一次,因此,对单个信号事件调用多次。

    如我们使用信号在保存模型时发送电子邮件,则传递唯一标识符作为dispatch_uid参数,以识别接收函数。这个标识符通常是一个字符串。

    最终结果是,对于每个唯一的信号,我们的接收器函数将只绑定到该信号一次。

    from django.core.signals import request_finished

    request_finished.connect(my_receiver, dispatch_uid="my_unique_identifier")

  如我们注册时保存密码需要用到post_save,新建my_signals.py,在文件中加入下面代码:

  from django.db.models.signals import post_save

  from django.dispatch import receiver

  from django.contrib.auth import get_user_model

  user = get_user_model()

  @receiver(signal=post_save, sender=user)

  def create_user(sender, instance=None, created=False, **kwarg):

    password = instance.password

    instance.set_password(password)

    instance.save()

  然后在项目apps中重写ready,将我们新建的my_signals引入即可

  

3、自定义信号

  1)定义信号:

    在项目根目录新建文件self_signal.py

    import django.dispatch

    my_signal = django.dispatch.Signals(providing_args=["aaa","bbb"])

  2)注册信号(即信号接收器)

    项目应用下的__init__.py文件

    from self_signal import my_signal

    def register_my_signal(sender, **kwargs):

      print("my signal msg:", sender, **kwargs)

    my_signal.connect(register_my_signal)

  3)触发信号

    views视图中编写如下:

      from self_signal import my_signal

      my_signal.send(sender="Python", aaa=111, bbb=2)

      

Django signals 信号作用及用法说明的更多相关文章

  1. django signals 信号

    django signals 信号 配置方式 app下的 __init__.py default_app_config="web.apps.WebConfig" #初始化app配置 ...

  2. Django signals机制的几个简单问题

    1.Django signals机制不是异步执行,是同步执行,所以需要异步执行的耗时任务不能用这个. 2.异步耗时任务不用这个,那些用signals?主要是解耦那些多次重复场合被调用的函数.直接用事件 ...

  3. Django之信号和序列化

    前言 Django的信号要从一张抽象图和一个需求说起: 赛道:Django 赛车:http请求 基础设施:Django设置的信号 一.Django内置信号类型 1.既然赛道上有各种基础设置,那么Dja ...

  4. Django 之 信号机制

    Django 之 信号机制 Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) . 当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行 ...

  5. Celery-4.1 用户指南: Signals (信号)

    基础 有多种类型的事件可以触发信号,你可以连接到这些信号,使得在他们触发的时候执行操作. 连接到 after_task_publish 信号的示例: from celery.signals impor ...

  6. Django 的信号 & Flask 的信号

    信号:框架内部已帮助开发者预留的可扩展的位置 一.Django 的信号 项目目录结构: django_signal |--- app01 |--- models.py |--- views.py .. ...

  7. serialVersionUID, ObjectInputStream与ObjectOutputStream类,Serializable接口,serialVersionUID的作用和用法

    ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入 Ser ...

  8. Oracle函数over(),rank()over()作用及用法--分区(分组)求和& 不连续/连续排名

    (1)   函数:  over()的作用及用法:    -- 分区(分组)求和. RANK ( ) OVER ( [query_partition_clause] order_by_clause )D ...

  9. Linq中关键字的作用及用法

    Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...

随机推荐

  1. 前后端分离djangorestframework——权限组件

    权限permissions 权限验证必须要在认证之后验证 权限组件也不用多说,读了源码你就很清楚了,跟认证组件很类似 具体的源码就不展示,自己去读吧,都在这里: 局部权限 设置model表,其中的ty ...

  2. ASP.NET MVC从视图传参到控制器的几种形式

    1. 传递数组 $(function () { var value = ["C#", "JAVA", "PHP"]; $("inp ...

  3. hivesql优化的深入解析

    转载:https://www.csdn.net/article/2015-01-13/2823530 一个Hive查询生成多个Map Reduce Job,一个Map Reduce Job又有Map, ...

  4. Linux CPU占用率监控工具小结

    关键词:top.perf.sar.ksar.mpstat.uptime.vmstat.pidstat.time.cpustat.munin.htop.glances.atop.nmon.pcp-gui ...

  5. ubuntu 打开eclipse出现A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be ... 解决方法(转载)

    原创作者:http://www.cnblogs.com/jerome-rong/archive/2013/02/19/2916608.html Java RunTime Environment (JR ...

  6. IntelliJ IDEA LicenseServer激活及使用

    一.激活 IntelliJ IDEA下载地址:https://www.jetbrains.com/idea/download/#section=windows 原文地址:http://blog.csd ...

  7. React项目中那些奇怪的写法

    1.在一个React组件里看到一个奇怪的写法: const {matchs} = this.props.matchs; 原来,是解构赋值,虽然听说过,但是看起来有点奇怪 下面做个实验: <scr ...

  8. 【ZJOI2012】灾难

    [ZJOI2012]灾难 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学 ...

  9. 局域网下Android与scoket通信的实现

    因为最近实验室项目要求实现在局域网下将android app数据发送到winsock中进行保存,所以对此进行了简单学习.pc端因为是另一个同学做的,所以不做说明. 在android端,首先添加权限: ...

  10. java 生成txt文件

    FileWriter fileWriter = new FileWriter("C:/Users/li/Desktop/a.txt"); fileWriter.write(“aaa ...