1

am having difficulties understanding how signals works, I went through some pages but none of them helped me get the picture.

I have two models, I would like to create a signal that will save in the child model when a record is saved in the parent. Actually, I want the child to be listening across my application for any parent since this child in particular of a generic foreign key.

core/models.py

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class Audit(models.Model):
    ## TODO: Document
    # Polymorphic model using generic relation through DJANGO content type
    operation  = models.CharField(max_length=40)
    operation_at = models.DateTimeField("Operation At", auto_now_add=True)
    operation_by = models.ForeignKey(User, db_column="operation_by", related_name="%(app_label)s_%(class)s_y+")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

workflow/models.py

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from core.models import Audit


class Instances(models.Model):
    ##  TODO: Document
    ##  TODO: Replace id with XXXX-XXXX-XXXX-XXXX
    # Re
    INSTANCE_STATUS = (
        ('I', 'In Progress' ),
        ('C', 'Cancelled'   ),
        ('D', 'Deleted'     ),
        ('P', 'Pending'     ),
        ('O', 'Completed'   )
    )

    id=models.CharField(max_length=200, primary_key=True)
    status=models.CharField(max_length=1, choices=INSTANCE_STATUS, db_index=True)
    audit_obj=generic.GenericRelation(Audit, editable=False, null=True, blank=True)


    def save(self, *args, **kwargs):
        # on new records generate a new uuid
        if self.id is None or self.id.__len__() is 0:
            import uuid
            self.id=uuid.uuid4().__str__()
        super(Instances, self).save(*args, **kwargs)



class Setup(models.Model):
    ## TODO: Document
    # Polymorphic model using generic relation through DJANGO content type
    content_type=models.ForeignKey(ContentType)
    object_id=models.PositiveIntegerField()
    content_object=generic.GenericForeignKey('content_type', 'object_id')


class Actions(models.Model):
    ACTION_TYPE_CHOICES = (
        ('P', 'Python Script'),
        ('C', 'Class name'),
    )
    name=models.CharField(max_length=100)
    action_type=models.CharField(max_length=1, choices=ACTION_TYPE_CHOICES)


class Tasks(models.Model):
    name=models.CharField(max_length=100)
    Instance=models.ForeignKey(Instances)

Am struggling to create a listener in Audit model so I can connect it with Instance model, If a new record inserted in Instance it will automatically inserts one in Audit as well. Then, am planning to connect this listener to several models in my app,

Any idea how I can do such a thing?

Mo J. Mughrabi
  • 6,747
  • 16
  • 85
  • 143
  • 1
    Here's what's important: Why? Since the child has an FK to the parent, the child's `save()` can simply call the parent's `save()`. You don't need signals for this. – S.Lott Dec 31 '10 at 15:46

1 Answers1

4

With the code below you can connect the save of an Instance object, with the after_save_instance_handler method. In this method you create the relation to the Audit. Please also see the generic relations doc

I usually add the signals in the models.py where the sender has been defined. Not sure if this is needed.

from django.db.models.signals import post_save

#####SIGNALS######
def after_save_instance_handler(sender, **kwargs):
    #get the saved instance
    instance_object = kwargs['instance']

    #get the needed data
    the_date = ...
    the_user = ...
    the_object_id = ...

    #create the relation to the audit object
    instance_object.audit_obj.create(operation="op963",operation_at=the_date,operation_by=the_user,object_id=the_object_id)

#connect the handler with the post save signal - django 1.1 + 1.2
post_save.connect(after_save_instance_handler, sender=Instances)

django 1.2 signals

in django development version they added a decorator to connect the signal. thus instead of the call above you have to add this decorator to the handler

@receiver(post_save, sender=Instances)
def after_save_instance_handler(sender, **kwargs):

django dev signals

Thomas Kremmel
  • 14,575
  • 26
  • 108
  • 177
  • Tom, this code you wrote is amazing! I already tried it with some models and it worked perfectly. Although, I have a problem getting it working with Instances model in specific. Apparently, because am importing/using Audit class inside Instances, Django throws an error when i try importing Instances inside Audit. It cannot see the class I get the following error ImportError: cannot import name Instances – Mo J. Mughrabi Jan 01 '11 at 08:34
  • You're welcome!so you want to import Instances in Audit? are these models placed in the same models.py? If yes, is the Instances model defined after Audit? If yes, one think come up to my mind. Not sure about importing, but at least with setting a ForeignKey, the model referenced has to be placed above the referencing model. – Thomas Kremmel Jan 01 '11 at 12:11