Django signals 信號做用及用法說明

參考:https://docs.djangoproject.com/en/1.11/ref/signals/數據庫

一、Model signalsdjango

  django.db.models.signales 做用於django的model操做上的一系列信號app

  1)pre_init()ide

    django.db.models.signals.pre_init函數

    當模型實例化時調用,在__init__()以前執行post

    三個參數:測試

      pre_init(sender, args, kwargs):ui

        sender:建立實例的模型類spa

        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內部使用,通常不會被第三方應用使用。

 

二、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請求過程當中遇到錯誤時發送。

 

三、使用信號

  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引入便可

  

 

三、自定義信號

  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)

相關文章
相關標籤/搜索