Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
List all signals by model and signal type. Tested with Django 3.
# -*- coding: utf-8 -*-
# Based on https://gist.github.com/voldmar/1264102
# and https://gist.github.com/runekaagaard/2eecf0a8367959dc634b7866694daf2c
import gc
import inspect
import weakref
from collections import defaultdict
from django.apps import apps
from django.core.management.base import BaseCommand
from django.db.models.signals import (
ModelSignal, pre_init, post_init, pre_save, post_save, pre_delete,
post_delete, m2m_changed, pre_migrate, post_migrate
)
from django.utils.encoding import force_str
MSG = '{module}.{name} #{line}'
SIGNAL_NAMES = {
pre_init: 'pre_init',
post_init: 'post_init',
pre_save: 'pre_save',
post_save: 'post_save',
pre_delete: 'pre_delete',
post_delete: 'post_delete',
m2m_changed: 'm2m_changed',
pre_migrate: 'pre_migrate',
post_migrate: 'post_migrate',
}
class Command(BaseCommand):
help = 'List all signals by model and signal type'
def handle(self, *args, **options):
all_models = apps.get_models(include_auto_created=True, include_swapped=True)
model_lookup = {id(m): m for m in all_models}
signals = [obj for obj in gc.get_objects() if isinstance(obj, ModelSignal)]
models = defaultdict(lambda: defaultdict(list))
for signal in signals:
signal_name = SIGNAL_NAMES.get(signal, 'unknown')
for receiver in signal.receivers:
lookup, receiver = receiver
if isinstance(receiver, weakref.ReferenceType):
receiver = receiver()
if receiver is None:
continue
receiver_id, sender_id = lookup
model = model_lookup.get(sender_id, '_unknown_')
if model:
models[model][signal_name].append(MSG.format(
name=receiver.__name__,
module=receiver.__module__,
line=inspect.getsourcelines(receiver)[1],
path=inspect.getsourcefile(receiver))
)
output = []
for key in sorted(models.keys(), key=str):
verbose_name = force_str(key._meta.verbose_name)
output.append('{}.{} ({})'.format(
key.__module__, key.__name__, verbose_name))
for signal_name in sorted(models[key].keys()):
lines = models[key][signal_name]
output.append(' {}'.format(signal_name))
for line in lines:
output.append(' {}'.format(line))
return '\n'.join(output)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment