zoukankan      html  css  js  c++  java
  • Django signals 信号作用及用法说明

    参考: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)

          

  • 相关阅读:
    深入Android 【一】 —— 序及开篇
    Android中ContentProvider和ContentResolver使用入门
    深入Android 【六】 —— 界面构造
    The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the ser
    Dynamic Business代码片段总结
    对文件的BuildAction以content,resource两种方式的读取
    paraview 3.12.0 windows下编译成功 小记
    百度网盘PanDownload使用Aria2满速下载
    netdata的安装与使用
    用PS给证件照排版教程
  • 原文地址:https://www.cnblogs.com/fiona-zhong/p/9983996.html
Copyright © 2011-2022 走看看