Добавление дополнительных данных в результаты Django Rest Framework для всего набора результатов

Я использую 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": [
        {...}
    ]
}

Дополнительные подсчеты в этом примере - это только то, сколько объектов имеет полевое расстояние со значением, меньшим миль, описанных в ключе.

Моя проблема в том, что я понятия не имею, где лучшее место для расширения и вставки этого поведения.

В идеале, мне бы хотелось, чтобы это работало независимо от того, были ли страницы разбиты на страницы или нет, не допуская никаких предположений.

То, что я на самом деле после этого, - это кивка в правильном направлении (и почему это подходящее место для него).

Я проверил документы и не могу найти ничего, что описывает, как добавлять такие вещи, но я был бы более чем счастлив, если бы оказался ошибочным на этот счет.

Ответ 1

Поскольку вы, похоже, используете один из ListViews из Rest Framework, вы можете переопределить метод 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

Обратите внимание, что ваш класс должен наследовать ListModelMixin напрямую или через GenericView из API Rest Framework (http://www.django-rest-framework.org/api-guide/generic-views#listmodelmixin). Я действительно не знаю, правильно ли это делать, но это быстрое решение.

Надеюсь, поможет!

Ответ 2

Используйте SerializerMethodField, как указано в этом решении.

Его можно использовать для добавления любых данных в сериализованное представление вашего объекта. (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 

Я также добавил аннотацию расстояния к каждому объекту в наборе запросов для работы фильтрации.