【问题标题】:Adding extra data to Django Rest Framework results for entire result set为整个结果集向 Django Rest Framework 结果添加额外数据
【发布时间】:2014-08-01 14:00:24
【问题描述】:

我正在使用 Django Rest Framework,需要向结果集中添加额外的数据。具体来说,您通常会在哪里:

{
    "count": 45, 
    "next": "http://localhost:8000/foo/bar?page=2", 
    "previous": null, 
    "results": [
        {...}
    ]
}

我想像这样添加额外的计数:

{
    "count": 45,
    "10_mi_count": 10,
    "20_mi_count": 30,
    "30_mi_count": 45,
    "next": "http://localhost:8000/foo/bar?page=2", 
    "previous": null, 
    "results": [
        {...}
    ]
}

此示例中的额外计数只是有多少对象的场距离值小于键中描述的英里数。

我的问题是我不知道扩展和插入此行为的最佳位置在哪里。

理想情况下,无论结果是否分页,我都希望它能够正常工作,不做任何假设。

我真正追求的是朝着正确的方向点头(以及为什么这是正确的去处)。

我查看了文档,找不到任何描述如何添加此类内容的内容,但我很乐意在这方面被证明是错误的。

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    由于您似乎使用的是 Rest Framework 中的 ListView 之一,您可以覆盖类中的 list() 方法并在结果数据上设置新值,如下所示:

        def list(self, request, *args, **kwargs):
            response = super().list(request, args, kwargs)
            # Add data to response.data Example for your object:
            response.data['10_mi_count'] = 10 # Or wherever you get this values from
            response.data['20_mi_count'] = 30
            response.data['30_mi_count'] = 45
            return response
    

    请注意,您的类必须直接或通过来自 Rest Framework API (http://www.django-rest-framework.org/api-guide/generic-views#listmodelmixin) 的 GenericView 继承 ListModelMixin。我真的不知道这是否是正确的方法,但它是一个快速修复。

    希望对你有帮助!

    【讨论】:

    • 嘿,我最后采用了另一种方法,我在自己的答案中已经描述了这种方法。这是一个很好的选择,非常感谢。
    • 我做了一个效果很好的变体。我想要一些汇总的最小-最大数据与我的查询一起返回一些滑块范围。我将 list 方法的实现从父类完全复制到我的子类中。它获取查询集对象,因此我可以修改它以在查询集上运行聚合并将结果添加到响应中。谢谢!
    【解决方案2】:

    使用SerializerMethodField 中提到的solution

    它可用于将任何类型的数据添加到对象的序列化表示中。 (REST framework doc)

    文档中的示例:

    from django.contrib.auth.models import User
    from django.utils.timezone import now
    from rest_framework import serializers
    
    class UserSerializer(serializers.ModelSerializer):
        days_since_joined = serializers.SerializerMethodField()
    
        class Meta:
            model = User
    
        def get_days_since_joined(self, obj):
            return (now() - obj.date_joined).days
    

    【讨论】:

    【解决方案3】:

    最后,我刚刚创建了一个自定义分页序列化器,其中包含如下字段:

    class DistanceCountField(serializers.Field):
        def to_native(self, value):
            try:
                distance_counts = {
                    '1_mile': self._count_lte_miles(value, 1),
                    '5_mile': self._count_lte_miles(value, 5),
                    '10_mile': self._count_lte_miles(value, 10),
                    '20_mile': self._count_lte_miles(value, 20),
                }
            except FieldError:
                distance_counts = None
    
            return distance_counts
    
        def _count_lte_miles(self, value, miles):
            meters = miles * 1609.344
            return value.filter(distance__lte=meters).count()
    
    
    class PaginatedCountSerializer(pagination.PaginationSerializer):
        distance_counts = DistanceCountField(source='paginator.object_list')
    
        class Meta:
            # Class omitted, just a standard model serializer
            object_serializer_class = MyModelSerializer 
    

    我还为查询集中的每个对象添加了一个距离注释,以便进行过滤。

    【讨论】:

      【解决方案4】:

      我也将 DRF 与分页一起使用,并且想添加返回的查询集本身的摘要,所以首先我必须在 list 方法中获取查询集。

      def list(self, request, *args, **kwargs):
          queryset = self.filter_queryset(self.get_queryset())
          summary = {}
          summary['x'] = queryset.filter(transaction_type='x').count()
          summary['y'] = queryset.filter(transaction_type='y').count()
      
          page = self.paginate_queryset(queryset)
          if page is not None:
              serializer = self.get_serializer(page, many=True)
              data = {}
              data['summary'] = summary
              data['details'] = serializer.data
              return self.get_paginated_response(data)
      
      
          serializer = self.get_serializer(queryset, many=True)
          data = {}
          data['summary'] = summary
          data['details'] = serializer.data
          return Response(data)
      

      这给了我以下回应:

      {
        "count": 20,
        "next": "http://..",
        "previous": null,
        "results": {
          "summary": {
            "x": 15,
            "y": 5,
          },
          "details": [
            {.....
      

      注意:这也适用于非分页结果。

      【讨论】:

        【解决方案5】:

        我在这里捎带接受的答案!

        我认为主要问题是序列化程序返回一个 ReturnList,它只是一个带有一些额外上下文的常规列表。

        您可以像这样用自己的 OrderedDict 替换数据:

        response = super().list(request, *args, **kwargs)
        new_data = OrderedDict()
        new_data.update({
            'results': response.data,
            '10-mi-count': 10,
            #etc...
        })
        response.data = new_data
        
        return response 
        

        【讨论】:

          猜你喜欢
          • 2016-09-14
          • 2011-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-12
          • 1970-01-01
          相关资源
          最近更新 更多