深入学习Django源码基础16 - django中信号的学习分析

在django中有1个比较好玩的技术。那就是信号的绑定和接受技术。

从项目开发的角度,django中的信号处理技术属于辅助功能。流程并不清晰。

django提供的信号有

class_prepared = Signal(providing_args=["class"])

pre_init = Signal(providing_args=["instance", "args", "kwargs"])
post_init = Signal(providing_args=["instance"])

pre_save = Signal(providing_args=["instance", "raw", "using", "update_fields"])
post_save = Signal(providing_args=["instance", "raw", "created", "using", "update_fields"])

pre_delete = Signal(providing_args=["instance", "using"])
post_delete = Signal(providing_args=["instance", "using"])

post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])

m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"])

request_started = Signal()
request_finished = Signal()
got_request_exception = Signal(providing_args=["request"])

分析信号的原理。可以看出来。

在信号内部主要通过receiver和sender(允许为None)的key组合来保存信号槽。

当send发送信号时候。通过遍历信号槽列表。判断sender是否允许。如果允许,则调用函数。

有1点可以确定的是,信号使用的是单件方式。也就是说要全局唯一性。使用太多对性能是一种负担。因此最好只实现Django自带的就可以了。


下面是抽出来的演示代码

from django.dispatch import saferef
import weakref

def _make_id(target):
    if hasattr(target, '__func__'):
        return (id(target.__self__), id(target.__func__))
    return id(target)

import threading
WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)

class Signal(object):

    def __init__(self):
        self.receivers = []
        self.lock = threading.Lock()

    def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
        import inspect
        assert callable(receiver) , "Signal receivers must be callable."

        try:
            argspec = inspect.getargspec(receiver.__call__)
        except (TypeError, AttributeError):
            argspec = None
        if argspec:
            assert argspec[2] is not None, \
                    "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:
            receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)

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

    def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
        if dispatch_uid:
            loopup_key = (dispatch_uid, _make_id(sender))
        else:
            loopup_key = (_make_id(receiver), _make_id(sender))

        with self.lock:
            for index in xrange(len(self.receivers)):
                (r_key, _) = self.receivers[index]
                if r_key == loopup_key:
                    del self.receivers[index]
                    break

    def has_listeners(self, sender=None):
        return bool(self._live_receivers(_make_id(sender)))

    def send(self, sender, **named):
        responses = []
        if not self.receivers:
            return responses

        for receiver in self._live_receivers(_make_id(sender)):
            response = receiver(signal=self, sender=sender, **named)
            responses.append((receiver, response))
        return responses

    def _live_receivers(self, senderkey):
        none_senderkey = _make_id(None)
        receivers = []

        for (receiverKey, r_senderkey), receiver in self.receivers:
            if r_senderkey == none_senderkey or r_senderkey == senderkey:
                if isinstance(receiver, WEAKREF_TYPES):
                    receiver = receiver()
                    if receiver is not None:
                        receivers.append(receiver)
                else:
                    receivers.append(receiver)
        return receivers

    def _remove_receiver(self, receiver):
        with self.lock:
            to_remove = []
            for key, connected_receiver in self.receivers:
                if connected_receiver == receiver:
                    to_remove.append(key)
            for key in to_remove:
                last_idx = len(self.receivers) - 1
                for idx, (r_key, _)  in enumerate(reversed(self.receivers)):
                    if r_key == key:
                        del self.receivers[last_idx - idx]



signal_demo = Signal()

def reset_queries(**kwargs):
    print 'reset_querys [%s]' % str(kwargs)
signal_demo.connect(reset_queries)

class objDemo(object):
    def click(self):
        signal_demo.send(sender=self.__class__, request={"1":1})

obj = objDemo()
obj.click()

打印输出

reset_querys [{'signal': <__main__.Signal object at 0x109be5290>, 'request': {'1': 1}, 'sender': <class '__main__.objDemo'>}]


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值