0

I'm working on a Django model and I want to trigger a function every time its variables change. Here's my model:

class Cv(models.Model):
    name = models.CharField(max_length=100)
    position = models.ForeignKey(
        OpenPosition,
        on_delete=models.CASCADE,
        null=True,
    )
    team = models.ForeignKey(
        Team,
        on_delete=models.CASCADE,
        null=True
    )
    leader = models.ForeignKey(Leader, on_delete=models.CASCADE)

    email = models.EmailField(
        max_length=100,
        null=False,
        validators=[EmailValidator()],
        blank=True
    )
    email_sent_status = models.BooleanField(default=False)
    phone = models.CharField(
        validators=[
            RegexValidator(
                regex=r'^(0\d{9,11})$',
                message='''
                Phone number must be started with 0 and has 10-12 digits
                '''
            )],
        blank=True,
        null=True,
        max_length=20,
    )
    link = models.CharField(
        max_length=150,
        validators=[URLValidator()],
    )
    source = models.ForeignKey(CvSource, on_delete=models.CASCADE)
    cv_status = models.CharField(
        max_length=10,
        choices=STATUS,
        default='u',
    )
    schedule = models.DateTimeField(blank=True, null=True)
    schedule_confirm = models.BooleanField(default=False)
    interview_status = models.CharField(
        max_length=10,
        choices=FULL_STATUS,
       default='u',
   )
   test_status = models.CharField(
       max_length=10,
       choices=STATUS,
       default='u',
    )
    test_comment = models.TextField(max_length=200, blank=True)
    decision_status = models.CharField(
        max_length=10,
        choices=FULL_STATUS,
        default='u',
    )
    offer_status = models.CharField(
        max_length=10,
        choices=OFFER_STATUS,
        default='u,'
    )
    internal_comment = models.TextField(max_length=200, blank=True)
    created_at = models.DateTimeField(
        editable=False,
        null=True,
    )
    updated_by = models.CharField(max_length=30, editable=False, null=True)

Currently I'm using an approach that is mentioned in Django: When saving, how can you check if a field has changed? but with many variables this process become repetitive:

def __init__(self, *args, **kwargs):
    super(Cv, self).__init__(*args, **kwargs)
    #override original fields' values with current values
    self.__original_schedule = self.schedule
    self.__original_schedule_confirm = self.schedule_confirm
    self.__original_name = self.name
    self.__original_position = self.position
    self.__original_team = self.team
    self.__original_leader = self.leader
    self.__original_email = self.email
    self.__original_email_sent_status = self.email_sent_status
    self.__original_phone = self.phone
    #etc

def save(self, *args, **kwargs):
    if self.__original_schedule != self.schedule: 
        #do something etc

I want to find a way to optimize this process. I have read somewhere that you can use @property to track variables' changes and I want to know if I can use this approach in my model. If not, is there any other way i can improve my method.

badiya
  • 2,247
  • 13
  • 23
Hoang V. Pham
  • 189
  • 1
  • 2
  • 9
  • Using properties might interfere with Django's ORM and other magic. But you have many options: signals, validators, overwrite `save()`, a setter method... – Klaus D. Jul 13 '17 at 05:29

1 Answers1

4

Why not django signals? see docs here

post_save signal is fired every time you save a model object.

Working example :

In your models.py add..

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Cv)
def hear_signal(sender , instance , **kwargs):
    if kwargs.get('created'):
        return # if a new model object is created then return. You need to distinguish between a new object created and the one that just got updated.

    #Do whatever you want. 
    #Your trigger function content.
    #Parameter "instance" will have access to all the attributes of the model being saved. To quote from docs : It's "The actual instance being saved."        

    return

Thanks. Hope this helps.

Shivam Sharma
  • 901
  • 1
  • 6
  • 12