Skip to content

Instantly share code, notes, and snippets.

@ezheidtmann
Created August 8, 2017 20:55
Show Gist options
  • Save ezheidtmann/85fcea99ee4c5c070cbea41ed921ea8e to your computer and use it in GitHub Desktop.
Save ezheidtmann/85fcea99ee4c5c070cbea41ed921ea8e to your computer and use it in GitHub Desktop.
Receive Django signals for a model (workaround for bug in built-in sender filtering)
def model_instance_signal_receiver(signal, Model):
"""Register signal receiver for a specific model
When using QuerySet.defer(), the model objects are instances of a subclass, so
the built-in sender matching doesn't work. This approach uses that subclassing
to ensure we run the receiver for both deferred and non-deferred instances.
As a side effect, this also allows you to register a receiver for all
subclasses of an abstract model.
"""
from django.dispatch import receiver
def decorator(fn):
@receiver(signal)
@wraps(fn)
def wrapper(sender, **kwargs):
if issubclass(sender, Model):
instance = kwargs.pop('instance')
if instance is not None:
kwargs['sender'] = sender
return fn(instance, **kwargs)
return wrapper
return decorator
@ezheidtmann
Copy link
Author

Example usage:

@model_instance_signal_receiver(post_save, models.Trip)
def update_brief_stats(trip, **kwargs):
    if kwargs.get('created'):
        pass
    else:
        logger.info('Trip modified')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment