Adding extra data to Django Rest Framework results for entire result set

后端 未结 4 1328
刺人心
刺人心 2020-12-14 15:42

I\'m using Django Rest Framework and need to add extra data to a result set. Specifically, where you would usually have:

{
    \"count\": 45, 
    \"next\":          


        
相关标签:
4条回答
  • 2020-12-14 15:49

    In the end I just created a custom pagination serializer with a field like so:

    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 
    

    I also added a distance annotation to each object in the queryset for the filtering to work on.

    0 讨论(0)
  • 2020-12-14 15:50

    I used DRF with pagination as well and wanted to add a summary of the returned queryset itself, so first I had to get the queryset in the list method.

    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)
    

    This gave me the following response:

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

    Note: this will work for non-paginated results as well.

    0 讨论(0)
  • 2020-12-14 16:03

    Use SerializerMethodField as mentioned in this solution.

    It can be used to add any sort of data to the serialized representation of your object. (REST framework doc)

    Example from the documentation:

    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
    
    0 讨论(0)
  • 2020-12-14 16:04

    Since you seem to be using one of the ListViews from the Rest Framework, you could override the list() method in your class and set new values on the resulting data, like this:

        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
    

    Notice that your class must inherit the ListModelMixin directly or via a GenericView from the Rest Framework API (http://www.django-rest-framework.org/api-guide/generic-views#listmodelmixin). I really don't know if it is the right way to do this, but it is a quick fix.

    Hope it helps!

    0 讨论(0)
提交回复
热议问题