Проблемы с суммированием и вычитанием в Django и PostgreSQL

У меня проблема с квери (получение суммы элемента (агрегата) и вычитание.

).

Что я пытаюсь сделать: 10 (soldfor) - 2 (paid) - 2 (shipcost) = 6

Проблема в том, что если я добавлю еще один (soldfor) (paid) или (shipcost) = он сложит их все, так что прибыль станет двойной. Другой пример, если у меня есть товар с (paid), указанным в 3.56 и другой товар с тем же (paid) int, он вычитает эти два из каждой новой строки. Я попробовал два запроса и не могу заставить их работать.

Что я получаю: 10 (soldfor) - 2 (paid) - 2 (shipcost) = 12, потому что два поля имеют одинаковый точный ввод.

По сути, если два поля имеют одинаковый номер, он добавляет или вычитает их к каждой строке, которая имеет такое же поле с таким же номером.

models.py

class Inventory(models.Model):
    product = models.CharField(max_length=50)
    description = models.CharField(max_length=250)
    paid = models.DecimalField(null=True, max_digits=5, decimal_places=2)
    bin = models.CharField(max_length=4)
    listdate = models.DateField(null=True, blank=True)
    listprice = models.DecimalField(null=True, max_digits=5, decimal_places=2, blank=True)
    solddate = models.DateField(null=True, blank=True)
    soldprice = models.DecimalField(null=True, max_digits=5, decimal_places=2, blank=True)
    shipdate = models.DateField(null=True, blank=True)
    shipcost = models.DecimalField(null=True, max_digits=5, decimal_places=2, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateField(auto_now=True)

    def __str__(self):
        return self.product + "\n" + self.description + "\n" + self.paid + self.bin + "\n" + self.listdate + "\n" + self.listprice + "\n" + self.solddate + "\n" + self.soldprice + "\n" + self.shipdate + "\n" + self.shipcost

    @property
    def Calculate_profit(self):
        soldfor = Inventory.objects.filter(soldprice=self.soldprice).aggregate(Sum('soldprice'))['soldprice__sum'] or 0.00 
        paidfor = Inventory.objects.filter(paid=self.paid).aggregate(Sum('paid'))['paid__sum'] or 0.00 
        shipfor = Inventory.objects.filter(shipcost=self.shipcost).aggregate(Sum('shipcost'))['shipcost__sum'] or 0.00

        totalprofit = soldfor - paidfor - shipfor

        return totalprofit

и views.py

@login_required(login_url="/login")
def profitsperitem(request):
    inventory = Inventory.objects.filter(soldprice__isnull = False, shipcost__isnull = False).order_by('id')

    return render(request, 'portal/profitsperitem.html', {"inventory": inventory})

Я также пробовал просто выполнить этот запрос в views.py

  totals = Inventory.objects.aggregate(
            Sum('paid'),
            Sum('soldprice'),
            Sum('shipcost')
            )

    totalprofit = totals['soldprice__sum'] - totals['paid__sum'] - totals['shipcost__sum']

    return render(request, 'portal/profitsperitem.html', {"inventory": inventory, "totalprofit": totalprofit})

Как сделать так, чтобы это было только для данного товара, а не для других товаров, которые могут иметь такие же поля (soldfor) (paid) или (shipcost)?

Учитывая, что я понимаю, что вы пытаетесь сделать, вы можете просто работать с:

class Inventory(models.Model):
    # …

    def __str__(self):
        return f'{self.product}\n{self.description}\n{self.paid}{self.bin}\n{self.listdate}\n{self.listprice}\n{self.solddate}\n{self.soldprice}\n{self.shipdate}\n{self.shipcost}'

    @property
    def profit(self):
        return self.soldprice - self.paidfor - self.shipcost

Поскольку поля могут быть NULLable (что усложняет задачу), возможно, вам придется работать со значениями по умолчанию:

class Inventory(models.Model):
    # …

    @property
    def profit(self):
        return (self.soldprice or 0.00) - (self.paidfor or 0.00) - (self.shipcost or 0.00)

Но использование 0.00 в качестве "запасного значения" немного странно, если это NULL: NULL обычно означает "неизвестно", а не ноль. Поэтому в этом случае, если одно из полей равно None, мы возвращаем None:

class Inventory(models.Model):
    # …

    @property
    def profit(self):
        if self.soldprice is not None and self.paidfor is not None and self.shipcost is not None:
            return self.soldprice - self.paidfor - self.shipcost
Вернуться на верх