为整个结果集向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": [
{...}
]
}
在这个例子中,额外的计数就是指有多少个对象的“距离”这个字段的值小于关键字中描述的英里数。
我的问题是,我不知道在哪里扩展和插入这个功能才是最合适的。
理想情况下,我希望这个功能在结果是否分页的情况下都能正常工作,不想做任何假设。
我真正想要的是一个正确的方向指引(以及为什么这个地方是合适的)。
我查阅了文档,但找不到任何描述如何添加这些内容的信息,不过我很乐意被证明我错了。
5 个回答
我也使用了DRF(Django REST框架)和分页功能,并想要添加一个返回的查询集的总结。所以我首先需要在列表方法中获取这个查询集。
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": [
{.....
注意:这也适用于没有分页的结果。
我在这里借用一下被接受的答案!
我觉得主要的问题是,序列化器返回的是一个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
最后,我创建了一个自定义的分页序列化器,里面有一个字段,像这样:
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
我还给查询集中的每个对象添加了一个距离注释,这样过滤功能才能正常工作。
使用 SerializerMethodField,就像在这个 解决方案 中提到的那样。
它可以用来向你对象的序列化表示中添加任何类型的数据。 (REST框架文档)
以下是文档中的一个例子:
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
因为你似乎在使用Rest框架中的一个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
注意,你的类必须直接继承ListModelMixin,或者通过Rest框架API中的GenericView来继承(http://www.django-rest-framework.org/api-guide/generic-views#listmodelmixin)。我不太确定这是否是正确的方法,但这算是一个快速的解决办法。
希望这对你有帮助!