如何在 Django Rest Framework ModelViewSets 中添加聚合值

Posted

技术标签:

【中文标题】如何在 Django Rest Framework ModelViewSets 中添加聚合值【英文标题】:How to add aggregate values in Django Rest Framework ModelViewSets 【发布时间】:2021-12-07 00:05:07 【问题描述】:

在我的 DRF 应用中,我有以下模型、序列化程序和视图。

models.py

class Log(models.Model):
    plant = models.ForeignKey(Plant, on_delete=models.CASCADE)
    date_time = models.DateTimeField()
    water_consumption = models.PositiveSmallIntegerField()
    elec_consumption = models.PositiveSmallIntegerField()

序列化器.py

class ConsumptionSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Log
        fields = ("water_consumption", "elec_consumption")

views.py

class ConsumptionViewSet(viewsets.ModelViewSet):
    
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = ConsumptionSerializer

    def get_queryset(self):
        # Get params from url
        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get('end_date')
        # Make sure params are not null
        if start_date is not None and end_date is not None:
            queryset = queryset.filter(date_time__range=[start_date, end_date])
            return queryset
        else:
            raise ValidationError("ERROR": ["No params found in url"])
            

这行得通,它会在 JSON 中输出类似这样的内容:

[
    
        "water_consumption": 1,
        "electrical_consumption": 1
    ,
    
        "water_consumption": 1,
        "electrical_consumption": 1
    ,
    
        "water_consumption": 1,
        "electrical_consumption": 1
    ,
]

我想要实现的是在这些数据旁边接收一些聚合数据,如下所示:


    "total_water_consumption": 3,
    "total_elec_consumption": 3,
    "detailed_logs": [
        "water_consumption": 1,
        "electrical_consumption": 1
    ,
    
        "water_consumption": 1,
        "electrical_consumption": 1
    ,
    
        "water_consumption": 1,
        "electrical_consumption": 1
    ]

我应该如何自定义查询集以添加总值?

提前谢谢你。

【问题讨论】:

【参考方案1】:

您可以在序列化程序文件中使用SerializerMethodField 来完成

文档在:https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

您可以在序列化程序中以context 访问request

from django.db.models import Sum


class ConsumptionSerializer(serializers.ModelSerializer):
    total_water_consumption = serializers.SerializerMethodField()
    total_elec_consumption = serializers.SerializerMethodField()
    
    class Meta:
        model = Log
        fields = ("water_consumption", "elec_consumption")

    def get_total_water_consumption(self, obj):
        request = self.context['request']
        query_params = request.query_params.get(...)
        return Log.objects.filter(...).aggregate(Sum('water_consumption')).get('water_consumption__sum')

    def get_total_elec_consumption(self, obj):
        request = self.context['request']
        query_params = request.query_params.get(...)
        return Log.objects.filter(...).aggregate(Sum('elec_consumption')).get('elec_consumption__sum')

【讨论】:

你好@Amin,我试过了,但没有成功,因为过滤器依赖于每次请求时从 url 获取的参数,那么如何将这些传递给序列化程序? 我已经为你更新了答案@Giulia 非常感谢,这很有意义,我得到了它的工作。只是,这样它在所有日志中添加了聚合字段,是否可以在响应中只添加一次,然后是日志? 您可以为此使用嵌套序列化程序。有一个包含这两个聚合字段的序列化程序,以及一个名为 logs 的字段,例如,它与您之前的序列化程序嵌套。然后将您的项目作为 logs 关键字传递给序列化程序... @Giulia 或者你可以在你的序列化器中覆盖to_represention() 方法。或者将这些汇总字段附加到您之前的最终结果views@Giulia

以上是关于如何在 Django Rest Framework ModelViewSets 中添加聚合值的主要内容,如果未能解决你的问题,请参考以下文章

Django.rest_framework:如何序列化一对多?

如何使用 TemplateHTMLRenderer 在 Django-REST-Framework 中创建/放置?

django-rest-framework:如何序列化已经包含 JSON 的字段?

如何在 Django Rest Framework 中散列 Django 用户密码?

如何仅使用 django 作为后端并使用 django-rest-framework 发布

如何在 React 中显示来自 django-rest-framework 的错误消息