diff --git a/django/db/models/base.py b/django/db/models/base.py
index 71fd1f7..730e52f 100644
a
|
b
|
from django.db.models.query_utils import DeferredAttribute
|
18 | 18 | from django.db.models.deletion import Collector |
19 | 19 | from django.db.models.options import Options |
20 | 20 | from django.db.models import signals |
| 21 | from django.db.models.signals import pre_init, post_init |
21 | 22 | from django.db.models.loading import register_models, get_model |
22 | 23 | from django.utils.translation import ugettext_lazy as _ |
23 | 24 | from django.utils.functional import curry |
… |
… |
class Model(object):
|
277 | 278 | _deferred = False |
278 | 279 | |
279 | 280 | def __init__(self, *args, **kwargs): |
280 | | signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) |
| 281 | pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) |
281 | 282 | |
282 | 283 | # Set up the storage for instance state |
283 | 284 | self._state = ModelState() |
… |
… |
class Model(object):
|
367 | 368 | if kwargs: |
368 | 369 | raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) |
369 | 370 | super(Model, self).__init__() |
370 | | signals.post_init.send(sender=self.__class__, instance=self) |
| 371 | post_init.send(sender=self.__class__, instance=self) |
371 | 372 | |
372 | 373 | def __repr__(self): |
373 | 374 | try: |
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
index 48872e7..65e8f23 100644
a
|
b
|
from django.dispatch import Signal
|
2 | 2 | |
3 | 3 | class_prepared = Signal(providing_args=["class"]) |
4 | 4 | |
5 | | pre_init = Signal(providing_args=["instance", "args", "kwargs"]) |
6 | | post_init = Signal(providing_args=["instance"]) |
| 5 | pre_init = Signal(providing_args=["instance", "args", "kwargs"], use_caching=True) |
| 6 | post_init = Signal(providing_args=["instance"], use_caching=True) |
7 | 7 | |
8 | | pre_save = Signal(providing_args=["instance", "raw", "using"]) |
9 | | post_save = Signal(providing_args=["instance", "raw", "created", "using"]) |
| 8 | pre_save = Signal(providing_args=["instance", "raw", "using"], use_caching=True) |
| 9 | post_save = Signal(providing_args=["instance", "raw", "created", "using"], use_caching=True) |
10 | 10 | |
11 | | pre_delete = Signal(providing_args=["instance", "using"]) |
12 | | post_delete = Signal(providing_args=["instance", "using"]) |
| 11 | pre_delete = Signal(providing_args=["instance", "using"], use_caching=True) |
| 12 | post_delete = Signal(providing_args=["instance", "using"], use_caching=True) |
13 | 13 | |
14 | | post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"]) |
| 14 | post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"], use_caching=True) |
15 | 15 | |
16 | | m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"]) |
| 16 | m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"], use_caching=True) |
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index ed9da57..bd9e461 100644
a
|
b
|
def _make_id(target):
|
9 | 9 | if hasattr(target, 'im_func'): |
10 | 10 | return (id(target.im_self), id(target.im_func)) |
11 | 11 | return id(target) |
| 12 | NONE_ID = _make_id(None) |
12 | 13 | |
13 | 14 | class Signal(object): |
14 | 15 | """ |
… |
… |
class Signal(object):
|
20 | 21 | { receriverkey (id) : weakref(receiver) } |
21 | 22 | """ |
22 | 23 | |
23 | | def __init__(self, providing_args=None): |
| 24 | def __init__(self, providing_args=None, use_caching=False): |
24 | 25 | """ |
25 | 26 | Create a new signal. |
26 | 27 | |
… |
… |
class Signal(object):
|
31 | 32 | if providing_args is None: |
32 | 33 | providing_args = [] |
33 | 34 | self.providing_args = set(providing_args) |
| 35 | self.use_caching = use_caching |
| 36 | # For convenience we create empty caches even if they are not used |
| 37 | self.sender_no_receivers_cache = set() |
| 38 | self.sender_receivers_cache = {} |
34 | 39 | self.lock = threading.Lock() |
35 | 40 | |
36 | 41 | def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): |
… |
… |
class Signal(object):
|
107 | 112 | else: |
108 | 113 | self.receivers.append((lookup_key, receiver)) |
109 | 114 | finally: |
| 115 | if self.use_caching: |
| 116 | self.sender_no_receivers_cache = set() |
| 117 | self.sender_receivers_cache = {} |
110 | 118 | self.lock.release() |
111 | 119 | |
112 | 120 | def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None): |
… |
… |
class Signal(object):
|
144 | 152 | del self.receivers[index] |
145 | 153 | break |
146 | 154 | finally: |
| 155 | if self.use_caching: |
| 156 | self.sender_no_receivers_cache = set() |
| 157 | self.sender_receivers_cache = {} |
147 | 158 | self.lock.release() |
148 | 159 | |
149 | 160 | def send(self, sender, **named): |
… |
… |
class Signal(object):
|
165 | 176 | Returns a list of tuple pairs [(receiver, response), ... ]. |
166 | 177 | """ |
167 | 178 | responses = [] |
168 | | if not self.receivers: |
| 179 | if not self.receivers or (self.use_caching and sender in self.sender_no_receivers_cache): |
169 | 180 | return responses |
170 | 181 | |
171 | | for receiver in self._live_receivers(_make_id(sender)): |
| 182 | for receiver in self._live_receivers(sender): |
172 | 183 | response = receiver(signal=self, sender=sender, **named) |
173 | 184 | responses.append((receiver, response)) |
174 | 185 | return responses |
… |
… |
class Signal(object):
|
197 | 208 | receiver. |
198 | 209 | """ |
199 | 210 | responses = [] |
200 | | if not self.receivers: |
| 211 | if not self.receivers or (self.use_caching and sender in self.sender_no_receivers_cache): |
201 | 212 | return responses |
202 | 213 | |
203 | 214 | # Call each receiver with whatever arguments it can accept. |
204 | 215 | # Return a list of tuple pairs [(receiver, response), ... ]. |
205 | | for receiver in self._live_receivers(_make_id(sender)): |
| 216 | for receiver in self._live_receivers(sender): |
206 | 217 | try: |
207 | 218 | response = receiver(signal=self, sender=sender, **named) |
208 | 219 | except Exception, err: |
… |
… |
class Signal(object):
|
211 | 222 | responses.append((receiver, response)) |
212 | 223 | return responses |
213 | 224 | |
214 | | def _live_receivers(self, senderkey): |
| 225 | def _live_receivers(self, sender): |
215 | 226 | """ |
216 | 227 | Filter sequence of receivers to get resolved, live receivers. |
217 | 228 | |
218 | 229 | This checks for weak references and resolves them, then returning only |
219 | 230 | live receivers. |
220 | 231 | """ |
221 | | none_senderkey = _make_id(None) |
222 | | receivers = [] |
223 | | |
224 | | for (receiverkey, r_senderkey), receiver in self.receivers: |
225 | | if r_senderkey == none_senderkey or r_senderkey == senderkey: |
226 | | if isinstance(receiver, WEAKREF_TYPES): |
227 | | # Dereference the weak reference. |
228 | | receiver = receiver() |
229 | | if receiver is not None: |
230 | | receivers.append(receiver) |
231 | | else: |
| 232 | receivers = None |
| 233 | if self.use_caching: |
| 234 | receivers = self.sender_receivers_cache.get(sender) |
| 235 | if receivers is None: |
| 236 | none_senderkey = NONE_ID |
| 237 | senderkey = _make_id(sender) |
| 238 | receivers = [] |
| 239 | if self.use_caching: |
| 240 | self.lock.acquire() |
| 241 | for (receiverkey, r_senderkey), receiver in self.receivers: |
| 242 | if r_senderkey == none_senderkey or r_senderkey == senderkey: |
232 | 243 | receivers.append(receiver) |
233 | | return receivers |
| 244 | if self.use_caching: |
| 245 | if not receivers: |
| 246 | self.sender_no_receivers_cache.add(sender) |
| 247 | # Note, we must cache the weakref versions. |
| 248 | self.sender_receivers_cache[sender] = receivers |
| 249 | self.lock.release() |
| 250 | non_weak_receivers = [] |
| 251 | for receiver in receivers: |
| 252 | if isinstance(receiver, WEAKREF_TYPES): |
| 253 | # Dereference the weak reference. |
| 254 | receiver = receiver() |
| 255 | if receiver is not None: |
| 256 | non_weak_receivers.append(receiver) |
| 257 | else: |
| 258 | non_weak_receivers.append(receiver) |
| 259 | return non_weak_receivers |
234 | 260 | |
235 | 261 | def _remove_receiver(self, receiver): |
236 | 262 | """ |
237 | 263 | Remove dead receivers from connections. |
238 | 264 | """ |
239 | | |
240 | 265 | self.lock.acquire() |
241 | 266 | try: |
242 | 267 | to_remove = [] |
… |
… |
class Signal(object):
|
251 | 276 | if r_key == key: |
252 | 277 | del self.receivers[last_idx-idx] |
253 | 278 | finally: |
| 279 | if self.use_caching: |
| 280 | self.sender_no_receivers_cache = set() |
| 281 | self.sender_receivers_cache = {} |
254 | 282 | self.lock.release() |
255 | 283 | |
256 | 284 | |