1from functools import partial
2
3from django.db.models.utils import make_model_tuple
4from django.dispatch import Signal
5
6class_prepared = Signal()
7
8
9class ModelSignal(Signal):
10 """
11 Signal subclass that allows the sender to be lazily specified as a string
12 of the `app_label.ModelName` form.
13 """
14
15 def _lazy_method(self, method, apps, receiver, sender, **kwargs):
16 from django.db.models.options import Options
17
18 # This partial takes a single optional argument named "sender".
19 partial_method = partial(method, receiver, **kwargs)
20 if isinstance(sender, str):
21 apps = apps or Options.default_apps
22 apps.lazy_model_operation(partial_method, make_model_tuple(sender))
23 else:
24 return partial_method(sender)
25
26 def connect(self, receiver, sender=None, weak=True, dispatch_uid=None, apps=None):
27 self._lazy_method(
28 super().connect,
29 apps,
30 receiver,
31 sender,
32 weak=weak,
33 dispatch_uid=dispatch_uid,
34 )
35
36 def disconnect(self, receiver=None, sender=None, dispatch_uid=None, apps=None):
37 return self._lazy_method(
38 super().disconnect, apps, receiver, sender, dispatch_uid=dispatch_uid
39 )
40
41
42pre_init = ModelSignal(use_caching=True)
43post_init = ModelSignal(use_caching=True)
44
45pre_save = ModelSignal(use_caching=True)
46post_save = ModelSignal(use_caching=True)
47
48pre_delete = ModelSignal(use_caching=True)
49post_delete = ModelSignal(use_caching=True)
50
51m2m_changed = ModelSignal(use_caching=True)
52
53pre_migrate = Signal()
54post_migrate = Signal()