Search code examples
djangodjango-modelsdjango-signals

Django: How to update model instance using pre_save signal?


I want to create a pre_save signal which will update the already created model instance whenever the sender is updated. I want to do it in pre_save signal.

The previous instance of the model will be either deleted and new instance will be created or the previous instance will be updated.

My models:

class Sales(models.Model):
    user            = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
    company         = models.ForeignKey(Company,on_delete=models.CASCADE,null=True,blank=True)
    party_ac        = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='partyledgersales')
    sales           = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='saleledger')
    date            = models.DateField(default=datetime.date.today,blank=False, null=True)
    sub_total       = models.DecimalField(max_digits=10,decimal_places=2,blank=True, null=True)

class Journal(models.Model):
    user            = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
    company         = models.ForeignKey(Company,on_delete=models.CASCADE,null=True,blank=True,related_name='Companyname')
    voucher_id      = models.PositiveIntegerField(blank=True,null=True)
    date            = models.DateField(default=datetime.date.today)
    by              = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='Debitledgers')
    to              = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='Creditledgers')
    debit           = models.DecimalField(max_digits=10,decimal_places=2,null=True)
    credit          = models.DecimalField(max_digits=10,decimal_places=2,null=True)

My pre_save signal for creation:

@receiver(pre_save, sender=Sales)
def user_created_sales(sender,instance,*args,**kwargs):
    if instance.sub_total != None:
            Journal.objects.update_or_create(user=instance.user,company=instance.company,date=instance.date,voucher_id=instance.id,by=instance.party_ac,to=instance.sales,debit=instance.sub_total,credit=instance.sub_total)

I want to create a signal which will update the Journal instance whenever the sender model or Sales model is update or delete the previous instance or create a new one.

Any idea how to perform this?

Thank you


Solution

  • update_or_create takes two sets of parameters:

    • kwargs which are the parameters that uniquely identify the row to fetch from the database
    • defaults which are the parameters that should be updated

    Right now, you're never updating existing instances of Journal because you haven't specified defaults. You're looking for instances that match all the parameters, if one exists, you don't do anything, if it doesn't exist you create it.

    You haven't told us what makes a Journal entry unique (and how it relates to a Sales entry, since there is no ForeignKey relationship between them). update: with voucher_id, you now have way of looking up the corresponding Journal entries.

    But something like:

    Journal.objects.update_or_create(
        user=instance.user,
        company=instance.company,
        voucher_id=instance.id,
        defaults={
            'date': instance.date,
            'debit': instance.sub_total,
            'credit': instance.sub_total,
            'by': instance.party_ac,
            'to': instance.sales}
    )
    

    would look for existing instance with the same user, company, and voucher_id and update the date, by, to, credit and debit.