Использование агрегата в свойстве модели Django

Описание схемы

enter image description here

Проект может иметь несколько элементов проекта, а элемент проекта может иметь несколько затрат на приобретение. Например, капитальный проект № 1 содержит два элемента проекта:

  • Кол-во. 1 приобретенное оборудование
    • Одна стоимость приобретения в размере 5000 долларов США за приобретение оборудования у поставщика.
  • Кол-во. 1 испытательная арматура, построенная персоналом
    • Двенадцать 1000 покупок за каждую общую стоимость приобретения в размере 12 000 долларов.

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

Желание

Я хочу иметь возможность определить общие затраты на приобретение для каждого элемента, и я хочу иметь возможность определить общие затраты на приобретение для каждого проекта. На основании приведенного выше примера:

  • Общая стоимость приобретения 1-го уровня = 5000 долларов США
  • Общая стоимость приобретения 2-го уровня = $12 000
  • Общая стоимость приобретения капитального проекта = $17 000.

Вопросы

  • Если total_acquisition_costs рассчитывается с использованием агрегатов Django или сохраняется как DecimalField на моделях Project и ProjectItem?
  • Должен ли я создать свойство total_acquisition_costs для моделей ProjectItem и Project? Мне кажется, что да, чтобы создать свойство.

    Мне нравится вычислять значения с помощью агрегатов, чтобы избежать денормализации базы данных. В частности, я склоняюсь к использованию функции агрегирования Django Sum для создания свойства total_acquisition_costs. Тем не менее, я не собираюсь вкладывать агрегат в модель в качестве свойства, чтобы он просто возвращал значение вместо словаря.

Текущий код

Примечание. Мой текущий код не использует возможности агрегации Django, но он работает.

class ProjectItem(models.Model):
    project = models.ForeignKey(CapExProject)
    name = models.CharField(max_length=128)

    @property
    def total_acquisition_costs(self):
        acquisition_costs = self.acquisitioncost_set.only(
                'amount')
        total_acquisition_costs = 0
        for acquisition_cost in acquisition_costs:
        total_acquisition_costs += acquisition_cost.amount
        return total_acquisition_costs

Ответ 1

Мне нравится ваша идея использовать Sum, но это свойство. Что-то вроде этого должно работать:

class Project(models.Model):
    @property
    def total_acquisition_costs(self):
        return AcquisitionCost.objects.filter(item__project=self).aggregate(total=Sum("amount"))["total"]

class ProjectItem(models.Model):
    @property
    def total_acquisition_costs(self):
        return self.acquisitioncost_set.aggregate(total=Sum("amount"))["total"]