Django Signals使用

定义Signals

Django自身提供了一些常见的signal,用户本身也可以定义自己需要的signal

定义signal很简单,只需要实例化一个Signal实例即可

实例化Signal时,可以传入关键词参数providing_args, providing_args是一个列表,列表中定义了当前signal调用send方法时可以传入的参数。

# django.core.signals.py

from django.dispatch import Signal

request_started = Signal(providing_args=["environ"])
request_finished = Signal()
got_request_exception = Signal(providing_args=["request"])
setting_changed = Signal(providing_args=["setting", "value", "enter"])

其中Signal的初始化也比较简单,就是为实例化的signal定义一个线程锁

class Signal(object):
    def __init__(self, providing_args=None, use_caching=False):
        self.receivers = []
        if providing_args is None:
            providing_args = []
        self.providing_args = set(providing_args)
        self.lock = threading.Lock()
        self.use_caching = use_caching
        # For convenience we create empty caches even if they are not used.
        # A note about caching: if use_caching is defined, then for each
        # distinct sender we cache the receivers that sender has in
        # 'sender_receivers_cache'. The cache is cleaned when .connect() or
        # .disconnect() is called and populated on send().
        self.sender_receivers_cache = weakref.WeakKeyDictionary() if use_caching else {}
        self._dead_receivers = False

定义Signal处理函数

Signal处理函数是一个函数或者是一个实例的方法,并且必须满足下面条件:

  1. hashable
  2. 可以接收关键词参数

其中处理函数必须包含的关键词参数有两个:

  • signal,要接收的Signal实例
  • sender,要接收的Signal触发者
# django.db.__init__.py

from django.core import signals
from django.db.utils import ConnectionHandler

connections = ConnectionHandler()


def reset_queries(**kwargs):
    for conn in connections.all():
        conn.queries_log.clear()
signals.request_started.connect(reset_queries)


def close_old_connections(**kwargs):
    for conn in connections.all():
        conn.close_if_unusable_or_obsolete()
signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

处理函数绑定Signal

django提供了两种方法可以将Signal的处理函数和Signal实例进行绑定:

  • 手动调用connect方法
  • 使用装饰器receiver

其实装饰器receiver最终还是调用了connect方法将处理函数和Signal实例进行绑定

Signal类的connect方法定义如下:

class Signal(object):

    ...
    
    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        from django.conf import settings

        # If DEBUG is on, check that we got a good receiver
        if settings.configured and settings.DEBUG:
            assert callable(receiver), "Signal receivers must be callable."

            # Check for **kwargs
            if not func_accepts_kwargs(receiver):
                raise ValueError("Signal receivers must accept keyword arguments (**kwargs).")

        if dispatch_uid:
            lookup_key = (dispatch_uid, _make_id(sender))
        else:
            lookup_key = (_make_id(receiver), _make_id(sender))

        if weak:
            ref = weakref.ref
            receiver_object = receiver
            # Check for bound methods
            if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):
                ref = WeakMethod
                receiver_object = receiver.__self__
            if six.PY3:
                receiver = ref(receiver)
                weakref.finalize(receiver_object, self._remove_receiver)
            else:
                receiver = ref(receiver, self._remove_receiver)

        with self.lock:
            self._clear_dead_receivers()
            for r_key, _ in self.receivers:
                if r_key == lookup_key:
                    break
            else:
                self.receivers.append((lookup_key, receiver))
            self.sender_receivers_cache.clear()

每个信号量根据receiver和sender都可以获取一个lookup_key可以唯一的标志一个Signal和其处理方法, 当调用Signal实例的connect方法时,会判断绑定的处理函数是否已经在自身receivers中,如果存在则不会重复注册

发送Singal

有了前面定义的Signal实例,以及定义的Signal实例处理方法,经过处理函数绑定Signal实例后就可以在必要的地方发送信号, 然后让绑定的处理函数处理了。

# django.core.handlers.wsgi.py

from threading import Lock

from django.core import signals
from django.core.handlers import base



class WSGIHandler(base.BaseHandler):

    ...

    def __call__(self, environ, start_response):

        ...
        
        signals.request_started.send(sender=self.__class__, environ=environ)
        
        ...

转载于:https://my.oschina.net/alazyer/blog/1568107

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django signals are a way to allow decoupled applications to get notified when certain actions occur elsewhere in the application. Signals are used to provide a way for different components of an application to communicate with each other without being tightly coupled. In Django, signals are dispatched by senders and received by receivers. A sender is typically an instance of a particular model class, and a receiver is a function that gets executed whenever the signal is sent. Signals can be created for various events, such as when an object is saved, deleted, or when a user logs in or logs out. To use signals in Django, you need to define a receiver function and connect it to the appropriate signal. This can be done in the `signals.py` file of your Django app. Here's an example: ```python from django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import MyModel @receiver(post_save, sender=MyModel) def my_receiver(sender, instance, created, **kwargs): # Do something when MyModel instance is saved if created: print("A new MyModel instance has been created!") else: print("A MyModel instance has been updated!") ``` In this example, the `my_receiver` function is decorated with the `@receiver` decorator, which connects it to the `post_save` signal of the `MyModel` class. The receiver function receives the sender (the `MyModel` class), the instance of the model being saved, and the `created` argument which indicates whether a new instance was created or an existing one was updated. By connecting receivers to signals, you can perform additional actions or trigger certain behaviors whenever specific events occur in your Django application.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值