【问题标题】:Can I perform queries in django pre_save signals?我可以在 django pre_save 信号中执行查询吗?
【发布时间】:2018-09-22 06:47:43
【问题描述】:

这是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)

我想使用 django 查询创建一个数学方程式,我的方程式结果将显示在 ledger1.Closing_Balance 字段中

所以我试过这个:

@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

django 有可能吗??? 因为如果我运行它,我会收到不支持的操作数错误...

这个有替代代码吗???

如果有人知道...请帮助

提前谢谢你

【问题讨论】:

    标签: python django django-models django-signals


    【解决方案1】:

    不支持的操作数异常与查询本身无关,而与你写的表达式有关:

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

    所以在这里您将QuerySets 与实际值一起添加,这没有任何意义。您可能想要使用的是.aggregate(..),然后将它包含的值包装出来,例如:

    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

    但话虽如此,使用信号来预先计算聚合通常不是一个好主意。例如,因为journal 对象可以更改其DebitCredit 值,这不会“触发”信号,因此不会进行更新。即使您还为此类事件添加逻辑,仍然可能发生信号未触发的情况,因为例如批量更新将超过信号系统。

    通常最好不要存储数据聚合,因为这会导致data duplication,就像文章所说的“滋生冗余和不一致。”。如果您想计算此类聚合,最好在数据库级别使用(物化)视图。

    编辑:查询本身似乎没有任何意义。如果您更新 ledger 记录,您可以执行过滤,并以这种方式计算更新:

    @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

    但这可能仍然不够,因为您需要对日期进行一些适当的过滤,等等。

    【讨论】:

    • 不,实际上我想要不同分类账的不同期末余额...如果我使用聚合所有分类账将是相同的...是否有可能执行此操作?
    • @NiladryKar:说不一样的ledgers,那你应该怎么把它存成一个instancepre_savepost_save 始终适用于 一个 实例。
    • 哦,是的,完全忘记了..你能给我提供另一种方法吗???@Willem Van Onsem
    • @NiladryKar:不知何故,你总是以 XY 问题告终,而不是解释 如何 你想解决问题,试着解释 你想解决什么。
    • 非常感谢@Willem Van Onsem...是的,我知道这只是完成了一半...非常感谢您提供给我这正是我想要的。 ..
    猜你喜欢
    • 2011-12-22
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 2014-04-15
    • 2011-09-03
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多