Могу ли я выполнять запросы в сигналах django pre_save? - PullRequest
0 голосов
/ 22 сентября 2018

Это 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 ???Потому что, если я запускаю это, я получаю неподдерживаемую ошибку операнда ...

Есть ли альтернативный код для этого ???

Если кто-нибудь знает это ... Plz help

Спасибо заранее

1 Ответ

0 голосов
/ 22 сентября 2018

Неподдерживаемое исключение операнда не имеет ничего общего с самим запросом, но с выражением, которое вы написали:

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

, поэтому здесь вы добавляете QuerySet s вместе с реальными значениями, а это неиметь смысл.Вероятно, вы хотели использовать .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 может изменить свое значение Debit или Credit, и это не "сработает" сигнал, следовательно, обновление не производится.Даже если вы добавите логику для таких событий, все равно может случиться, что сигналы не сработают, поскольку, например, массовое обновление превзойдет систему сигнализации.

Обычно лучше , а не хранить агрегаты данных, поскольку это приводит к дублированию данных , что, как и в статье, гласит: " порождает избыточность и несогласованность. ".Если вы хотите вычислить такие агрегаты, может быть лучше использовать (материализованное) представление на уровне базы данных.

EDIT : сам запрос, однако, не имеет никакого смысла.Если вы обновите запись 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

Но этого, вероятно, по-прежнему будет недостаточно, поскольку тогда вам потребуется выполнить некоторую надлежащую фильтрацию надата и т. д.

...