Calling a function after starting / deleting a Django model
I have a lot of model classes in Django. NONE of them have an overridden save () or delete () function.
I want to create a class level decorator that will be used to execute the post save () / delete () function. This class-level decorator must be shared so that all model classes can use it.
I've tried using signals for post_save and post_delete, but keeping a huge list of classes can be problematic. I want to avoid overriding save () / delete ().
Any suggestions on how to do this? Thanks in advance.
source to share
Have you tried creating a model class abstract
and subclassing all your actual models? This way, when you attach a signal pre_save
to the base class, it is sent whenever any child model is saved.
class SignaledModel(models.Model):
class Meta:
abstract = True
class Student(SignaledModel):
number = models.PositiveIntegerNumber(unique=True)
name = models.CharField(max_length=64)
class Course(SignaledModel):
code = models.CharField(unique=True)
teacher = models.CharField(max_length=64)
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=SignaledModel)
def model_post_save(sender, **kwargs):
print('Saved an instance with type: {}'.format(sender))
Whenever an instance of Course
or is saved Student
, it is called model_post_save
.
Hope it helps.
source to share
It is recommended to use the post_save signal.
If you don't want to register each model class individually, here is a solution with a class decorator:
from django.db.models.signals import post_save
from django.dispatch import receiver
class SaveRegister:
registered_classes = []
post_save_func = None
@classmethod
def register(cls, target_cls):
if not cls.post_save_func:
raise Exception("Post save function not defined")
if target_cls not in cls.registered_classes:
# prevent duplicate registration
cls.registered_classes.append(target_cls)
# register the model class to listen to post_save
receive(post_save, sender = target_cls)(cls.post_save_func)
# set the post_save signal handler
@classmethod
def set_post_save_func(cls, f):
cls.post_save_func = f
Now all you have to do is define the post_save handler once, set it to the SaveRegister class:
def model_post_save(sender, **kwargs):
print('Saved an instance with type: {}'.format(sender))
SaveRegister.set_post_save_func(model_post_save)
Each model class decorated SaveRegister.register
will automatically have a post_save handler:
@SaveRegister.register
class Student(SignaledModel):
number = models.PositiveIntegerNumber(unique=True)
name = models.CharField(max_length=64)
@SaveRegister.register
class Course(SignaledModel):
code = models.CharField(unique=True)
teacher = models.CharField(max_length=64)
source to share