我想使用模型管理器返回发票的项目和付款总额。 如果付款和项目模型中只有一条记录,它会正常工作,如果我添加更多记录,我将无法再链接结果。 在外壳中我尝试了以下
>>> Invoixe.objects.with_aggregates().last().tot
Decimal('60')
>>> Invoixe.objects.with_totals().last().tot
Decimal('30')
with_aggregates 返回错误的总计(tot)值(正确的总计是 30)
SQL 看起来像这样
SELECT
"task_invoixe"."id",
"task_invoixe"."name",
(CAST(SUM("task_ixem"."amount") AS NUMERIC)) AS "tot",
(CAST(SUM("task_paxment"."amount") AS NUMERIC)) AS "pay",
(CAST(((CAST(SUM("task_ixem"."amount") AS NUMERIC)) - (CAST(SUM("task_paxment"."amount") AS NUMERIC))) AS NUMERIC)) AS "bal"
FROM "task_invoixe"
LEFT OUTER JOIN "task_ixem" ON ("task_invoixe"."id" = "task_ixem"."invoixe_id")
LEFT OUTER JOIN "task_paxment" ON ("task_invoixe"."id" = "task_paxment"."invoixe_id")
GROUP BY "task_invoixe"."id", "task_invoixe"."name"
ORDER BY "task_invoixe"."id" ASC
LIMIT 1
这是代码 ChatGPT 认为这段代码应该可以工作 我可以通过像这样链接管理器来创建相同的错误
>>> Invoixe.objects.with_totals().with_payments().last().tot
Decimal('60')
>>> Invoixe.objects.with_totals().last().tot
Decimal('30')
这也给出了错误的金额
from django.db import models
from django.db.models import Sum, F
class InvoixeQueryset(models.QuerySet):
def with_totals(self):
return self.annotate(tot=Sum(F('ixem__amount')))
def with_payments(self):
return self.annotate(pay=Sum(F('paxment__amount')))
def with_aggregates(self):
return self.annotate(
tot=Sum('ixem__amount'),
pay=Sum('paxment__amount'),
).annotate(bal=F('tot') - F('pay'))
class InvoixeManager(models.Manager):
def get_queryset(self):
return InvoixeQueryset(self.model, using=self._db)
def with_aggregates(self):
return self.get_queryset().with_aggregates()
def with_totals(self):
return self.get_queryset().with_totals()
def with_payments(self):
return self.get_queryset().with_payments()
def with_balance(self):
return self.get_queryset().with_balance()
class Invoixe(models.Model):
name = models.CharField(max_length=80, unique=True)
objects = InvoixeManager()
def __str__(self):
return self.name
class Paxment(models.Model):
amount = models.DecimalField(
max_digits=20, decimal_places=2, default=0,
)
invoixe = models.ForeignKey('Invoixe', on_delete=models.CASCADE)
def __str__(self):
return str(self.amount)
class Ixem(models.Model):
amount = models.DecimalField(
max_digits=20, decimal_places=2, default=0,
)
invoixe = models.ForeignKey('Invoixe', on_delete=models.CASCADE)
def __str__(self):
return str(self.amount)
如果有人能够指导我找到正确的实现,我将非常感激。 谢谢。
我需要通过 Case 和 When 强制 Django 使用 group-by 还用一张表来存储借方和贷方,总体看起来更好。
def with_aggregates(self):
return self.annotate(
debit_sum=Sum(Case(When(ledger__action="DR", then=F('ledger__amount')), output_field=DecimalField())),
credit_sum=Sum(Case(When(ledger__action="CR", then=F('ledger__amount')), output_field=DecimalField()),
)
).annotate(
balance=(F('debit_sum') - F('credit_sum'))
)