Search code examples
djangodjango-signals

Django signals created value wrong return


I am generating a reference number to an objects field. If the record is new, the signal will fill other fields before saving. If the record is not new, I also have an action for it. I will check for an objects specific field and see if it changed and do some other action.

Here is a snippet of the signal function:

@receiver(pre_save, sender=ProofOfPayment)
def pre_save_for_proof_of_payment(sender, instance, created=False, **kwargs):
    print('created', created)
    if created:
        upload_date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        reference_number = 'PAYMENT-' + upload_date
        instance.reference_number = reference_number
        received = PaymentStatus.objects.get(pk=1) # Received
        instance.payment_status = received
    else:
        obj = sender.objects.get(pk=instance.pk)
        if not obj.payment_status == instance.payment_status:
            if instance.payment_status.name == 'Completed':
                instance.expiry_date = datetime.datetime.now() + datetime.timedelta(days=30)

I am simulating the process in the admin. I create a new record. When I create the new object, I get an error because the variable created is set to False, doing the else function in the snippet.

obj = sender.objects.get(pk=instance.pk) 

ProofOfPayment matching query does not exist.

I am not sure why the created value is set to False even if the record is new.

When I don't place a default value in the function:

def pre_save_for_proof_of_payment(sender, instance, created, **kwargs):

I get this error:

pre_save_for_proof_of_payment() missing 1 required positional argument: 'created'

When I set the default value to created=True, the signal does not get triggered when new record is made.

I am confused on how to use the created argument. What I knew is that Django will provide the boolean value based on if the record is new or not. But in this case, it is taking the default value once a new record is created.

What should be my default created boolean value such that I know when there is a new record as such in the if created: code block and when the record is not new such to trigger actions such as in the else codeblock.

My model goes like this.

class ProofOfPayment(models.Model):
    reference_number = models.CharField(max_length=500, blank=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL)
    payment_type = models.ForeignKey(
        PaymentType,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,)
    payment_status = models.ForeignKey(
        PaymentStatus,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,)
    receipt = models.FileField(
        upload_to='userproofofpayment',
        null=True,
        max_length=500)
    remarks = models.TextField(max_length=250, blank=True)
    upload_date = models.DateTimeField(auto_now_add=True)
    expiry_date = models.DateTimeField(blank=True, null=True)

    def __str__(self):
        return self.reference_number

Solution

  • You don't have created argument in pre_save signal. You have to use post_save for such logic.

    How can it say that's the object is created, when it's not saved yet?