django ListView с агрегированными данными из другой модели - PullRequest
1 голос
/ 07 мая 2020

Я хочу создать список моих проектов со сводкой элементов затрат, связанных с каждым проектом. Как это сделать в режиме просмотра django? Головная строка моей ожидаемой таблицы:

Project name, Sum cost of activities
Proj1   100
Proj2   150

Вот мои модели:

class Project(models.Model):
   name = CharField("Name",max_length=50)

class Activity(models.Model):
   cost = BigIntegerField("Cost", default=0)
   project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True,)

class ProjectListView(ListView):
    queryset = Project.objects.all()  #model = Project

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        ??? # want to calculate sum cost of activities somehow
        return data

1 Ответ

2 голосов
/ 07 мая 2020

Вы можете аннотировать Project s с помощью:

from django.db.models import Sum

class ProjectListView(ListView):
    queryset = Project.objects.annotate(<b>total_cost=Sum('activity__cost')</b>)

Project s, которые возникают из этого набора запросов, будут иметь дополнительный атрибут .total_cost, который содержит сумму cost s из связанных Activity s, поэтому в вашем шаблоне вы можете отобразить их, например, с помощью:

{% for project in object_list %}
    {{ project.name }}: {{ project<b>.total_cost</b> }}
{% endfor %}

Это создаст запрос, который будет выглядеть так:

SELECT project.*
       <b>SUM(activity.cost) AS total_cost</b>
FROM project
LEFT OUTER JOIN activity ON activity.project_id = project.id

Для Project s без связанных Activity объектов сумма будет NULL (т.е. None на уровне Python / Django). Вы можете использовать выражение Coalesce [Djang-doc] , чтобы использовать вместо 0:

from django.db.models import Sum, Value
from django.db.models.functions import Coalesce

class ProjectListView(ListView):
    queryset = Project.objects.annotate(
        <b>total_cost=Coalesce(</b>Sum('activity__cost')<b>, Value(0))</b>
    )
...