mirror of
				https://github.com/django/django.git
				synced 2025-11-04 09:57:47 +03:00 
			
		
		
		
	Fixed #18454 -- Added ability to pass a list of signals to receiver.
				
					
				
			Added ability to use receiver decorator in the following way:
    @receiver([post_save, post_delete], sender=MyModel)
    def signals_receiver(sender, **kwargs):
        ...
			
			
This commit is contained in:
		
							parent
							
								
									946d3d9f84
								
							
						
					
					
						commit
						d4da08375b
					
				| 
						 | 
				
			
			@ -257,14 +257,21 @@ class Signal(object):
 | 
			
		|||
def receiver(signal, **kwargs):
 | 
			
		||||
    """
 | 
			
		||||
    A decorator for connecting receivers to signals. Used by passing in the
 | 
			
		||||
    signal and keyword arguments to connect::
 | 
			
		||||
    signal (or list of signals) and keyword arguments to connect::
 | 
			
		||||
 | 
			
		||||
        @receiver(post_save, sender=MyModel)
 | 
			
		||||
        def signal_receiver(sender, **kwargs):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
        @receiver([post_save, post_delete], sender=MyModel)
 | 
			
		||||
        def signals_receiver(sender, **kwargs):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def _decorator(func):
 | 
			
		||||
        signal.connect(func, **kwargs)
 | 
			
		||||
        if isinstance(signal, (list, tuple)):
 | 
			
		||||
            [s.connect(func, **kwargs) for s in signal]
 | 
			
		||||
        else:
 | 
			
		||||
            signal.connect(func, **kwargs)
 | 
			
		||||
        return func
 | 
			
		||||
    return _decorator
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,6 +103,9 @@ Django 1.5 also includes several smaller improvements worth noting:
 | 
			
		|||
* In the localflavor for Canada, "pq" was added to the acceptable codes for
 | 
			
		||||
  Quebec. It's an old abbreviation.
 | 
			
		||||
 | 
			
		||||
* The :ref:`receiver <connecting-receiver-functions>` decorator is now able to
 | 
			
		||||
  connect to more than one signal by supplying a list of signals.
 | 
			
		||||
 | 
			
		||||
Backwards incompatible changes in 1.5
 | 
			
		||||
=====================================
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,10 +52,10 @@ called when the signal is sent by using the
 | 
			
		|||
:meth:`.Signal.connect` method:
 | 
			
		||||
 | 
			
		||||
.. method:: Signal.connect(receiver, [sender=None, weak=True, dispatch_uid=None])
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    :param receiver: The callback function which will be connected to this
 | 
			
		||||
        signal. See :ref:`receiver-functions` for more information.
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    :param sender: Specifies a particular sender to receive signals from. See
 | 
			
		||||
        :ref:`connecting-to-specific-signals` for more information.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +129,17 @@ receiver:
 | 
			
		|||
 | 
			
		||||
Now, our ``my_callback`` function will be called each time a request finishes.
 | 
			
		||||
 | 
			
		||||
Note that ``receiver`` can also take a list of signals to connect a function
 | 
			
		||||
to.
 | 
			
		||||
 | 
			
		||||
.. versionadded:: 1.3
 | 
			
		||||
 | 
			
		||||
The ``receiver`` decorator was added in Django 1.3.
 | 
			
		||||
 | 
			
		||||
.. versionchanged:: 1.5
 | 
			
		||||
 | 
			
		||||
The ability to pass a list of signals was added.
 | 
			
		||||
 | 
			
		||||
.. admonition:: Where should this code live?
 | 
			
		||||
 | 
			
		||||
    You can put signal handling and registration code anywhere you like.
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +189,7 @@ Preventing duplicate signals
 | 
			
		|||
In some circumstances, the module in which you are connecting signals may be
 | 
			
		||||
imported multiple times. This can cause your receiver function to be
 | 
			
		||||
registered more than once, and thus called multiples times for a single signal
 | 
			
		||||
event. 
 | 
			
		||||
event.
 | 
			
		||||
 | 
			
		||||
If this behavior is problematic (such as when using signals to
 | 
			
		||||
send an email whenever a model is saved), pass a unique identifier as
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,5 +4,5 @@ Unit-tests for the dispatch project
 | 
			
		|||
 | 
			
		||||
from __future__ import absolute_import
 | 
			
		||||
 | 
			
		||||
from .test_dispatcher import DispatcherTests
 | 
			
		||||
from .test_dispatcher import DispatcherTests, ReceiverTestCase
 | 
			
		||||
from .test_saferef import SaferefTests
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import gc
 | 
			
		|||
import sys
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
from django.dispatch import Signal
 | 
			
		||||
from django.dispatch import Signal, receiver
 | 
			
		||||
from django.utils import unittest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,8 @@ class Callable(object):
 | 
			
		|||
        return val
 | 
			
		||||
 | 
			
		||||
a_signal = Signal(providing_args=["val"])
 | 
			
		||||
b_signal = Signal(providing_args=["val"])
 | 
			
		||||
c_signal = Signal(providing_args=["val"])
 | 
			
		||||
 | 
			
		||||
class DispatcherTests(unittest.TestCase):
 | 
			
		||||
    """Test suite for dispatcher (barely started)"""
 | 
			
		||||
| 
						 | 
				
			
			@ -123,3 +125,29 @@ class DispatcherTests(unittest.TestCase):
 | 
			
		|||
        garbage_collect()
 | 
			
		||||
        a_signal.disconnect(receiver_3)
 | 
			
		||||
        self._testIsClean(a_signal)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReceiverTestCase(unittest.TestCase):
 | 
			
		||||
    """
 | 
			
		||||
    Test suite for receiver.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def testReceiverSingleSignal(self):
 | 
			
		||||
        @receiver(a_signal)
 | 
			
		||||
        def f(val, **kwargs):
 | 
			
		||||
            self.state = val
 | 
			
		||||
        self.state = False
 | 
			
		||||
        a_signal.send(sender=self, val=True)
 | 
			
		||||
        self.assertTrue(self.state)
 | 
			
		||||
 | 
			
		||||
    def testReceiverSignalList(self):
 | 
			
		||||
        @receiver([a_signal, b_signal, c_signal])
 | 
			
		||||
        def f(val, **kwargs):
 | 
			
		||||
            self.state.append(val)
 | 
			
		||||
        self.state = []
 | 
			
		||||
        a_signal.send(sender=self, val='a')
 | 
			
		||||
        c_signal.send(sender=self, val='c')
 | 
			
		||||
        b_signal.send(sender=self, val='b')
 | 
			
		||||
        self.assertIn('a', self.state)
 | 
			
		||||
        self.assertIn('b', self.state)
 | 
			
		||||
        self.assertIn('c', self.state)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user