Sumproduct с использованием агрегации Джанго - PullRequest
3 голосов
/ 30 марта 2010

Вопрос

Фон

Я моделирую счет, который может содержать несколько элементов. Отношение «многие ко многим» между моделями «Счет-фактура» и «Товар» обрабатывается с помощью промежуточной таблицы InvoiceItem.

Общая сумма счета-фактуры - amount_invoiced - рассчитывается путем суммирования произведения unit_price и quantity для каждого элемента в данном счете-фактуре. Ниже приведен код, который я сейчас использую для этого, но мне было интересно, есть ли лучший способ справиться с этим, используя возможности агрегирования Django .

Текущий код

class Item(models.Model):
    item_num = models.SlugField(unique=True)
    description = models.CharField(blank=True, max_length=100)


class InvoiceItem(models.Model):
    item = models.ForeignKey(Item)
    invoice = models.ForeignKey('Invoice')
    unit_price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.DecimalField(max_digits=10, decimal_places=4)


class Invoice(models.Model):
    invoice_num = models.SlugField(max_length=25)
    invoice_items = models.ManyToManyField(Item,through='InvoiceItem')

    def _get_amount_invoiced(self):
        invoice_items = self.invoiceitem_set.all()
        amount_invoiced = 0
        for invoice_item in invoice_items:
            amount_invoiced += (invoice_item.unit_price *
                invoice_item.quantity)
        return amount_invoiced

    amount_invoiced = property(_get_amount_invoiced)        

1 Ответ

2 голосов
/ 30 марта 2010

Да, это возможно начиная с Django 1.1, где были введены агрегатные функции. Вот решение для ваших моделей:

 def _get_amount_invoiced(self):
     self.invoiceitem_set.extra(select=("item_total": "quantity * unit_price")
                                ).aggregate(total=Sum("item_total")["total"]

Тем не менее, настоятельно рекомендуется хранить item_total в базе данных, поскольку он может подвергаться скидкам, налогам и другим изменениям, которые делают его вычисление в любой момент нецелесообразным или даже невозможным.

...