Django中訊號的實現
阿新 • • 發佈:2019-01-14
signal在django中用於傳送通知,在django中內建的訊號包括 post_save, pre_delete 等;使用這些訊號可以很方便實現業務邏輯與model之間的解耦。
內建signal的使用
django 內部有些定義好的signal供我們使用:
模型相關:
pre_save 物件save前觸發
post_save 物件save後觸發
pre_delete 物件delete前觸發
post_delete 物件delete後觸發
m2m_changed ManyToManyField 欄位更新後觸發
請求相關:
request_started 一個request請求前觸發 request_finished request請求後觸發
應用場景
適用於:當修改model的時候,需要執行一些與當前app無關額外的操作,比如邏輯中包含第三方的庫;執行的多個行為且後續仍可能新增操作等;
不適用:修改當前app中的某個model,這種場景建議放到save函式中執行;
適用場景,比如當用戶訂單支付成功之後,通常需要做以下事情
傳送郵件通知使用者支付成功
通知聊天程式(阿里旺旺)
通知賣家備貨
開始追蹤物流資訊
其他可能的行為…
以上行為都依賴於支付成功事件;如果上述行為寫到model的save() 函式中,就會使得業務邏輯緊耦合;推薦的做法是使用signal傳送一個通知到訊息佇列,其他的任務(程序)監聽訊息佇列,然後分別執行上述行為;
signal應用的例子:
order/models.py
class Order(models.Model): """ """ ORDER_STATUS = ( ("TRADE_CLOSED", "超時關閉"), ("PAYING", "待支付"), ("UNCONFIRMED", "待付款確認"), ("CONFIRMED", "已確認"), ) user = models.ForeignKey(UserModel, related_name="user_orders", verbose_name="使用者", db_index=True) # 訂單號規則,使用統一方法建立,主機id,程序號,時間ms+隨機數 order_sn = models.CharField(max_length=35, verbose_name="訂單號", null=True, blank=True, unique=True, db_index=True) trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name=u"交易號", db_index=True) pay_status = models.CharField(choices=ORDER_STATUS, default="PAYING", blank=True, max_length=30, verbose_name="訂單狀態") post_message = models.CharField(max_length=200, verbose_name="訂單留言", default="", blank=True, null=True) order_mount = models.FloatField(default=0.0, verbose_name="訂單金額") confirm_time = models.DateTimeField(null=True, blank=True, verbose_name="確認時間", default=None) create_time = models.DateTimeField(auto_now_add=True, verbose_name="建立時間") class Meta: verbose_name = u"訂單" verbose_name_plural = verbose_name
order/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Order)
def order_change(sender, instance=None, created=False, **kwargs):
if not created and instance:
if instance.pay_status == "CONFIRMED":
# 傳送訂單資訊到訊息佇列
apps.py
#這裡需要import signals檔案
from django.apps import AppConfig
from django.db.models.signals import post_save
class OrderConfig(AppConfig):
def ready(self):
import order.signals
可能遇到的問題
1、我們定義在signals.py檔案中的所有註冊事件都未執行
2、在signal中的部分註冊事件未執行
原因:
1、所有事件未執行–檢查是否在apps.py中import signals
2、部分註冊時間未執行-檢查是否註冊函式名重複
1、apps.py 檔案內import signals,執行向post_save 註冊回撥函式receiver
2、models執行save()時候,呼叫post_save的send()
3、send函式遍歷所有receiver並執行回撥函式(receiver 裝飾的自定義函式),因此我們的邏輯就會被執行;