DRF:聚合相似的条目名称

DRF: Aggregate similar entries name

我想按名称合并条目并对它们的其他字段执行添加。

在本例中,我想获取具有相同项目名称的条目的 total_cost 和 average_pct。

假设:

# models.py
class Project(models.Model):
    project = models.CharField(max_length=200)
    subproject = models.CharField(max_length=200)
    physical_pct = models.FloatField()
    cost = models.FloatField()

# serializers.py
class ProjectSerializer(serializers.ModelSerializer):

    class Meta:
        model = Project
        fields = '__all__'

# views.py
class ProjectsViewSet(viewsets.ModelViewSet):
    serializer_class = ProjectSerializer

    def get_queryset(self):
        queryset = Project.objects.all()
        return queryset

如果我有 3 个条目:

[
    {
        "project": "Project-X",
        "subproject": "Subproject-1",
        "physical_pct": 58,
        "cost": 1000.00
    },
    {
        "project": "Project-X",
        "subproject": "Subproject-2",
        "physical_pct": 100,
        "cost": 2000.00
    },
    {
        "project": "Project-Y",
        "subproject": "Subproject-1",
        "physical_pct": 73,
        "cost": 560.00
    }
]

我想要的输出:

[
    {
        "project": "Project-X",
        "average_pct": 79,
        "total_cost": 3000.00
    },
    {
        "project": "Project-Y",
        "average_pct": 73,
        "total_cost": 560.00
    }
]

更新 1:

values()的前提下,必须根据字段参数对相似条目进行分组。然而,当我尝试时,:

# serializers.py
class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = ['id', 'project', 'cost']

# views.py
from django.db.models import Avg, Sum

class ProjectsViewSet(viewsets.ModelViewSet):
    serializer_class = ProjectSerializer

    def get_queryset(self):
        queryset = Project.objects.values('project').\
                   annotate(total_cost=Sum('cost'))
        return queryset

我得到一个错误:

"Got KeyError when attempting to get a value for field `cost` on serializer `ProjectSerializer`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\nOriginal exception text was: 'cost'."

您可以在注释前使用 .values() 按项目分组。

from django.db.models import Avg, Sum

Project.objects.values('project').annotate(
    total_cost=Sum('cost'),
    average_pct=Avg('physical_pct'),
)

关于您的更新,由于分组,成本字段不存在于查询集中。 .values().annotate() 之外的字段中的 None 将出现。要在序列化程序中使用总成本,您需要使用 SerializerMethodField().

class ProjectSerializer(serializers.ModelSerializer):
    total_cost = serializers.SerializerMethodField()

    class Meta:
        model = Project
        fields = ['project', 'total_cost']

    def get_total_cost(self, instance):
        return instance.total_cost

如果您想用总成本而不是分组来注释每个实例,并且您使用的是 Django >= 2.0,那么您可以执行以下操作。

from django.db.models import F, Q, Sum

Project.objects.annotate(total_cost=Sum('cost', filter=Q(project=F('project'))))