Как агрегировать сумму поля модели класса в django

Я безуспешно пытаюсь показать total_net_interest на моей приборной панели. Я думаю, что это проблема с моей стратегией. Есть ли у кого-нибудь решение этой проблемы?

Модель

class Investment(models.Model):

    PLAN_CHOICES = (
        ("Basic - Daily 2% for 182 Days", "Basic - Daily 2% for 182 Days"),
        ("Premium - Daily 4% for 365 Days", "Premium - Daily 4% for 365 Days"),
    )
    plan = models.CharField(max_length=100, choices=PLAN_CHOICES, null=True)
    principal_amount = models.IntegerField(default=0, null=True)
    investment_id = models.CharField(max_length=10, null=True, blank=True)
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now=True, null=True)
    due_date = models.DateTimeField(null=True, blank=True)



    def daily_interest(self):
        if self.plan == "Basic - Daily 2% for 182 Days":
            return self.principal_amount * 365 * 0.02/2/182
        else:
            return self.principal_amount * 365 * 0.04/365 
    

    def net_interest(self):
        if self.plan == "Basic - Daily 2% for 182 Days":
            return self.principal_amount * 365 * 0.02/2
        else:
            return self.principal_amount * 365 * 0.04

    def total_net_interest(self):
        return self.Investment.aggregate(total_net_interest=Sum('net_interest'))['total_net_interest']

Как указано в комментариях, вы не можете агрегировать с помощью метода модели - однако, вы можете добавить net_interest в кверисет с помощью аннотации и затем агрегировать аннотированное поле.

Django .aggregate() на .annotate()

Вам, вероятно, потребуется использовать Case и When, чтобы применить вашу логику из этого метода.

Кроме того, в вашей модели PLAN_CHOICES скопированы оба значения, лучше было бы написать примерно так:


PLAN_BASIC = "basic"
PLAN_PREMIUM = "premium"

PLAN_CHOICES = (
        (PLAN_BASIC, "Basic - Daily 2% for 182 Days"),
        (PLAN_PREMIUM, "Premium - Daily 4% for 365 Days")
)

Это означает, что в базе данных хранятся только "basic" и "premium", но при этом будут отображаться введенные вами строки. Вы можете сделать что-то вроде Investment.PLAN_BASIC или self.PLAN_BASIC, в зависимости от контекста, чтобы убедиться, что вы не вводите строки в нескольких местах.

Вы должны annotate интересы в наборе запросов агрегировать на этой аннотации:

from django.db.models import Case, F, FloatField, Q, Sum, When

total = (Investment
         .objects
         .annotate(net=Case(When(Q(plan='Basic - Daily 2% for 182 Days'),
                                 then=F('principal_amount') * 365 * 0.01),
                            default=F('principal_amount') * 365 * 0.04,
                            output_field=FloatField))
         .aggregate(total=Sum('net')))['total']
Вернуться на верх