Django: base model signal handler does not fire

In the following code example:

from django.db import models from django.db.models.signals import pre_save # Create your models here. class Parent(models.Model): name = models.CharField(max_length=64) def save(self, **kwargs): print "Parent save..." super(Parent, self).save(**kwargs) def pre_save_parent(**kwargs): print "pre_save_parent" pre_save.connect(pre_save_parent, Parent) class Child(Parent): color = models.CharField(max_length=64) def save(self, **kwargs): print "Child save..." super(Child, self).save(**kwargs) def pre_save_child(**kwargs): print "pre_save_child" pre_save.connect(pre_save_child, Child) 

pre_save_parent does not work when creating a child:

 child = models.Child.objects.create(color="red") 

Is this the expected behavior?

+6
source share
2 answers

There is an open ticket, # 9318 .

Your workaround looks great. Here are two others offered on the ticket, benbest86 and alexr, respectively.

  • Listen to the signal of the child class and send the parent signal there.

     def call_parent_pre_save(sender, instance, created, **kwargs): pre_save.send(sender=Parent, instance=Parent.objects.get(id=instance.id), created=created, **kwargs) pre_save.connect(call_parent_pre_save, sender=Child) 
  • Do not specify the sender when connecting the signal, and then check the subclasses of the parent.

     def pre_save_parent(sender, **kwargs): if not isinstance(instance, Parent): return #do normal signal stuff here print "pre_save_parent" pre_save.connect(pre_save_parent) 
+6
source

I did not understand that sender was an optional parameter for connect . I can do the following:

 def pre_save_handler(**kwargs): instance = kwargs['instance'] if hasattr(instance, 'pre_save'): instance.pre_save() pre_save.connect(pre_save_handler) 

This allows me to write using the Model pre_save methods, and they, in turn, can call any version of the base class (if they exist).

Any better solutions?

+2
source

Source: https://habr.com/ru/post/898552/


All Articles