# Context manager

## TempDisconnectSignal

If you want to disable a signal from a django model temporarily, you can use this context manager. The great benefit
over disabling models the regular way is, that you cannot forget to enable the signal again. Secondly, you save one
line of code. Keep it DRY!

Image you have this setup:

````
from django.db import models
from django.db.models.signals import pre_save

class MyModel(models.Model):
    value = models.IntegerField()
    factor = models.IntegerField()
    product = models.IntegerField()


@receiver(pre_save, sender=MyModel)
def calculate_product(sender, instance, created, **kwargs):
    instance.product = value * factor
````

Now you want to save an instance of ``MyModel`` without calling the signal, you have to define at first a dictionary
with all parameters describing your signal:

````
from django.db.models import signals

signal_kwargs = {
    'signal': signals.pre_save,
    'receiver': calculate_product,
    'sender': MyModel,
}
````

With this information set, you can easily disable the signal like this:

````
my_obj = MyModel(value=1, factor=2)
with TempDisconnectSignal(**signal_kwargs):
    my_obj.save()
````

Now the attribute ``product`` will be not set / calculated.

If you need to disable the signal on multiple locations throughout your code, it is convenient to declare a method in
your model which provides the dictionary:


````
class MyModel(models.Model):
    ...

    @staticmethod
    def get_calculate_product_kwargs():
        return {
            'signal': signals.pre_save,
            'receiver': calculate_product,
            'sender': MyModel,
        }

...
with TempDisconnectSignal(**MyModel.get_calculate_product_kwargs()):
    my_obj.save()

````

Attention: If your signal has an explicit ``dispatch_uid``, you need to pass it to the context manager as well.

````
@receiver(pre_save, sender=MyModel, dispatch_uid='mymodel.calculate_product')
def calculate_product(sender, instance, created, **kwargs):
    instance.product = value * factor

...

signal_kwargs = {
    'signal': signals.pre_save,
    'receiver': calculate_product,
    'sender': MyModel,
    'dispatch_uid: 'mymodel.calculate_product',
}

...
````
