Skip to content

Instantly share code, notes, and snippets.

@RobertKolner
Last active August 15, 2018 10:11
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save RobertKolner/367ff95d4d3d3770fa7b to your computer and use it in GitHub Desktop.
Save RobertKolner/367ff95d4d3d3770fa7b to your computer and use it in GitHub Desktop.
[Note: for a better version, visit here: https://github.com/RobertKolner/django-signal-disabler] Temporarily disable all signals in django
from collections import defaultdict
from django.db.models.signals import *
class DisableSignals(object):
def __init__(self, disabled_signals=None):
self.stashed_signals = defaultdict(list)
self.disabled_signals = disabled_signals or [
pre_init, post_init,
pre_save, post_save,
pre_delete, post_delete,
pre_migrate, post_migrate,
]
def __enter__(self):
for signal in self.disabled_signals:
self.disconnect(signal)
def __exit__(self, exc_type, exc_val, exc_tb):
for signal in self.stashed_signals.keys():
self.reconnect(signal)
def disconnect(self, signal):
self.stashed_signals[signal] = signal.receivers
signal.receivers = []
def reconnect(self, signal):
signal.receivers = self.stashed_signals.get(signal, [])
del self.stashed_signals[signal]
# Example usage:
# with DisableSignals():
# user.save() # will not call any signals
@BeOleg
Copy link

BeOleg commented Feb 15, 2017

Any way to implement this is a decorator for test purposes?

@RobertKolner
Copy link
Author

RobertKolner commented Feb 21, 2017

Sorry @BeOleg that I didn't answer earlier, I didn't get any notification :(. Yes, it's entirely possible. To make it easier for everyone (including future-me), I converted this gist into a pip-package. I've also added an option for using it as a decorator: https://pypi.python.org/pypi/django-signal-disabler/

@skozlovskiy
Copy link

Got an error:

for signal in self.stashed_signals.keys():
RuntimeError: dictionary changed size during iteration

FIX:

   
    def __exit__(self, exc_type, exc_val, exc_tb):
        for signal in self.stashed_signals.keys():
            self.reconnect(signal)
        self.stashed_signals = defaultdict(list)  # <-- Add this

    def reconnect(self, signal):
        signal.receivers = self.stashed_signals.get(signal, [])
        # del self.stashed_signals[signal]  # <-- Remove this

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