简体   繁体   中英

Can I perform queries in django pre_save signals?

This is models.py

class ledger1(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='Companys')
    Creation_Date = models.DateField(default=datetime.now)
    name = models.CharField(max_length=32,unique=True)
    Opening_Balance = models.DecimalField(max_digits=19,decimal_places=2)
    Closing_balance = models.DecimalField(max_digits=10,decimal_places=2)


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')
    Date = models.DateField()
    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,)
    Credit = models.DecimalField(max_digits=10,decimal_places=2)

I want to make a mathamatical equation using django queries and the result of my equation will be displayed in the ledger1.Closing_Balance field

So I have tried this:

@receiver(pre_save, sender=ledger1)
def update_user_closing_balance(sender,instance,*args,**kwargs):
    Closing_balance = ledger1.objects.annotate(debitsum=Sum('Debitledgers__Debit')) + instance.Opening_Balance - ledger1.objects.annotate(creditsum=Sum('Creditledgers__Credit'))
    instance.Closing_balance = Closing_balance

Is it possible in django??? Because if I run this I am getting unsupported operand error...

Is there any alternative code for this???

If anyone knows it...Plz help

Thank you in advance

The unsupported operand exception has nothing to do with the query itself, but with the expression you wrote:

Closing_balance = (
   ledger1.objects.annotate(debitsum=Sum('Debitledgers__Debit')) +
   instance.Opening_Balance -
   ledger1.objects.annotate(creditsum=Sum('Creditledgers__Credit'))
)

so here you are adding QuerySet s together with real values, and that does not make any sense. What you probably wanted to use was an .aggregate(..) , and then wrap the value it contains out of it, like:

debitsum = ledger1.objects.aggregate(debitsum=Sum('Debitledgers__Debit'))['debitsum']
creditsum = ledger1.objects.aggregate(creditsum=Sum('Creditledgers__Credit'))['creditsum']

Closing_balance = debitsum + instance.Opening_Balance - creditsum

But that being said, using signals to pre-calculate aggregates is typically not a good idea. Since for example a journal object can change its Debit or Credit value, and this will not "fire" the signal, hence no update is done. Even if you also add logic for such events, it can still happen that the signals do not fire, since for example updating in bulk will surpass the signaling system.

Usually it is better not to store data aggregates, since this leads to data duplication which, like the article says " breeds redundancy and inconsistency. ". If you want to calculate such aggregates, it might be better to use a (materialized) view at the database level.

EDIT : the query itself however does not seem to make any sense. If you update a ledger record, you can perform a filtering, and calculate the update that way:

@receiver(pre_save, sender=ledger1)
def update_user_closing_balance(sender,instance,*args,**kwargs):
    debit = instance.Debitledgers.aggregate(debit=Sum('Debit'))['debit']
    credit = instance.Creditledgers.aggregate(credit=Sum('Credit'))['credit']
    instance.Closing_balance = instance.Opening_Balance + debit - credit

But this probably will still not suffice, since you will then need to do some proper filtering on the date, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM