Login

"Autoconnect" model decorator, easy pre_save and post_save signal connection

Author:
bendavis78
Posted:
July 24, 2010
Language:
Python
Version:
1.2
Tags:
pre_save post_save signal-connect
Score:
1 (after 1 ratings)

This method allows you to define pre_save and post_save signal connections for your decorators in a little more clean way. Instead of calling pre_save.connect(some_func, sender=MyModel), or perhaps pre_save.connect(MyModel.some_static_func, sender=MyModel), you can simply define the pre_save method right on your model. The @autoconnect decorator will look for pre_save and post_save methods, and will convert them to static methods, with "self" being the instance of the model.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# decorators.py

from functools import wraps
from django.db.models.signals import pre_save
from django.db.models.signals import post_save

def autoconnect(cls):
    """ 
    Class decorator that automatically connects pre_save / post_save signals on 
    a model class to its pre_save() / post_save() methods.
    """
    def connect(signal, func):
        cls.func = staticmethod(func)
        @wraps(func)
        def wrapper(sender, **kwargs):
            return func(kwargs.get('instance'))
        signal.connect(wrapper, sender=cls)
        return wrapper

    if hasattr(cls, 'pre_save'):
        cls.pre_save = connect(pre_save, cls.pre_save)

    if hasattr(cls, 'post_save'):
        cls.post_save = connect(post_save, cls.post_save)
    
    return cls 

#---------

# Example usage
@autoconnect
class MyModel(models.Model):
    foo = CharField(max_length=10,null=True,blank=True)
    bar = BooleanField()

    def pre_save(self):
        if self.foo is not None:
            self.bar = True

More like this

  1. Binding signals to abstract models by andreterra 3 years ago
  2. PreSaveMiddleware by pterk 7 years, 6 months ago
  3. Automatic slug generation signal by danux 3 years, 11 months ago
  4. Signal to post new saved objects to Twitter by arthurfurlan 6 years, 2 months ago
  5. Trigger a user password change by jedie 7 years, 8 months ago

Comments

mishudark (on July 24, 2010):

great snippet

#

Zah (on November 11, 2013):

This way you have them all!

import inspect
from functools import wraps
from django.db.models import signals

def autoconnect(cls):
    """ 
    Class decorator that automatically connects pre_save / post_save signals on 
    a model class to its pre_save() / post_save() methods.
    """
    issignal = lambda x: isinstance(x,signals.Signal)
    allsignals = inspect.getmembers(signals, issignal)
    def connect(signal, func):
        cls.func = staticmethod(func)
        @wraps(func)
        def wrapper(sender, **kwargs):
            return func(kwargs.get('instance'))
        signal.connect(wrapper, sender=cls)
        return wrapper

    for (name, method) in allsignals:
        if hasattr(cls, name):
            setattr(cls, name, connect(method, getattr(cls, name)))

    return cls

#

Please login first before commenting.