当前位置:脚本大全 > > 正文

django 获取请求参数(深入理解Django-Signals信号量)

时间:2022-01-28 01:17:12类别:脚本大全

django 获取请求参数

深入理解Django-Signals信号量

定义Signals

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

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

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • # 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定义一个线程锁

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 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. 可以接收关键词参数

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

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • # 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实例进行绑定:

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

    Signal类的connect方法定义如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 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实例后就可以在必要的地方发送信号, 然后让绑定的处理函数处理了。

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • # 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)
  •     
  •     ...
  • 信号量最为Django的一个核心知识点,在项目中很少有使用到,所以很多人都不了解或者没听过过(包括我)。简单来说就是在进行一些操作的前后我们可以发出一个信号来获得特定的操作,这些操作包括

    django.db.models.signals.pre_save&django.db.models.signals.post_save
    在模型 save()方法调用之前或之后发送。

    django.db.models.signals.pre_delete&django.db.models.signals.post_delete
    在模型delete()方法或查询集的delete() 方法调用之前或之后发送。

    django.db.models.signals.m2m_changed
    模型上的 ManyToManyField 修改时发送。

    django.core.signals.request_started&django.core.signals.request_finished
    Django开始或完成HTTP请求时发送。

    其他细致的知识点,大家可以点链接查看,直接通过一个例子解释:

    在自定义用户模型类的时候,在后台添加用户数据因为使用了自定义模型类的create所以密码会以明文保存,接下来使用信号量方式在保存后马上修改密码解决。(网上一个项目的例子)

    users/signals.py

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 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()
  •  
  •  
  • # post_save:上面七大方法之一:在模型保存之后的操作
  • # sender: 发出信号的model
  • @receiver(post_save, sender=User)
  • def create_user(sender, instance=None, created=False, **kwargs):
  •   """
  •   sender:模型类。
  •   instance:保存的实际实例。
  •   created:如果创建了新记录True。
  •   update_fields:Model.save()要更新的字段集,如果没有传递则为None
  •   """
  •   if created:
  •     password = instance.password
  •     # instance相当于user
  •     instance.set_password(password)
  •     instance.save()
  • users/apps.py

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • from django.apps import AppConfig
  •  
  •  
  • class UsersConfig(AppConfig):
  •   name = 'users'
  •   verbose_name = '用户管理'
  •  
  •   def ready(self):
  •   """使用ready加载,否则不生效"""
  •     import users.signals
  • 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持开心学习网。

    原文链接:https://segmentfault.com/a/1190000018195210

    上一篇下一篇

    猜您喜欢

    热门推荐