Использование агрегата в свойстве модели Django - PullRequest
11 голосов
/ 19 октября 2011

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

enter image description here

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

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

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

Желание

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

  • Позиция 1, общая стоимость приобретения = 5000 $
  • Позиция 2, общая стоимость приобретения = 12 000 долл. США
  • Капитальные затраты на приобретение проекта = 17 000 долл. США

Вопросы

  1. Следует ли total_acquisition_costs вычислять с использованием агрегатов Джанго или сохранять как DecimalField на моделях Project и ProjectItem?
  2. Должен ли я создать свойство total_acquisition_costs для моделей ProjectItem и Project? Я чувствую себя хорошо, чтобы создать собственность.

    Мне нравится вычислять значения с использованием агрегатов, чтобы избежать денормализации базы данных. В частности, я склоняюсь к использованию агрегатной функции 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 Ответ

13 голосов
/ 20 октября 2011

Мне нравится ваша идея использовать 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"]
...