Я использую Django 2.x
и Django REST Framework
.
У меня есть модель AmountGiven с полем свойства amount_due как
class AmountGiven(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
amount = models.FloatField(help_text='Amount given to the contact')
interest_rate = models.FloatField(blank=True, default=None, null=True, help_text='% of interest to be calculated')
total_due = models.FloatField(
blank=True,
default=0.0,
editable=False
)
@property
def interest_to_pay(self):
if self.interest_rate:
datetime_diff = datetime.now(get_localzone()) - datetime.combine(
self.given_date, datetime.min.time(), get_localzone()
)
days = datetime_diff.days
duration_in_year = days/365
simple_interest_amount = (self.amount * duration_in_year * self.interest_rate)/100
return simple_interest_amount
return 0
@property
def total_payable(self):
return self.amount + self.interest_to_pay
@property
def amount_due(self):
returned_amount = 0
for returned in self.amountreturned_set.all():
returned_amount += returned.amount
total_due = self.total_payable - returned_amount
self.total_due = total_due
self.save()
return total_due
Мне нужно сгенерировать данные графика для ответа Django REST Framework на общую сумму, подлежащую оплате для контакта.
def top_ten_due(request):
qs = Contact.objects.filter(
user=request.user
).values('first_name', 'last_name').annotate(
total_due=Sum('amountgiven__total_due')
).order_by(
'-total_due'
)[:10]
graph_data = []
for q in qs:
d = {
'contact': q['first_name'] if q['first_name'] else '' + ' ' + q['last_name'] if q['last_name'] else '',
'value': q['total_due'] if q['total_due'] else 0
}
graph_data.append(d)
return Response(sorted(graph_data, key=lambda i: i['value'], reverse=True))
Причитающаяся сумма рассчитывается как свойство amount_due модели AmountGiven . И для того, чтобы сгенерировать данные графика, мне нужно аннотировать соответствующую сумму. Поскольку я не могу аннотировать поле свойства, у меня есть поле только для чтения total_due , которое обновляется каждый раз, когда вызывается свойство amount_due . и затем используется в аннотации.
Таким образом, каждый раз, когда я вызываю объект AmountGiven , модель обновляется и, таким образом, запускается сигнал post_save .
Теперь имеется приемник сигнала post_save , который используется для создания журнала при каждом обновлении суммы.
@receiver(post_save, sender=AmountGiven, dispatch_uid='amountgiven12345')
def amount_given_post_save_receiver(sender, instance, created, **kwargs):
if created:
action = 'given'
else:
action = 'updated'
log = TransactionLog.objects.filter(
user=instance.contact.user,
contact=instance.contact,
amount_given=instance
).order_by('-created').first()
if not log or log.amount != instance.amount:
TransactionLog.objects.create(
user=instance.contact.user,
contact=instance.contact,
amount_given=instance,
amount=instance.amount,
action=action
)
Хотя я использовал эту проверку, чтобы проверить, не существует ли уже журнал или его количество отличается от количества экземпляров. Каждый раз, когда список AmountGiven выбирается, он запускает post_save для каждого запроса и, таким образом, receive срабатывает, что создает журнал.
Таким образом, он создает много журналов за короткий промежуток времени.
Как мне справиться с такой проблемой?
Могу ли я использовать поле свойства amount_due в любом случае в аннотации, чтобы total_due не обновлялось каждый раз, предотвращая вызов post_save ?