如何为序列化程序字段进行分页?
How to do pagination for a serializer field?
我有一项任务需要通过版主 ID 获取统计信息和反馈。 'stats' 字段是通用字段,'feedback' 字段是反馈列表。我可以为 'feedback' 字段分页吗?当然,我可以为统计数据和反馈设置不同的端点,但我不允许这样做。
// GET /api/moderators/:id/feedback
{
"stats": [
{
"name": "123",
"value": -10
}
],
"feedback": [
{
"id": 1,
"createdBy": "FN LN",
"createdAt": "DT",
"comment": "",
"score": 5,
"categories": [
{
"name": "123",
"status": "POSITIVE/NEGETIVE/UNSET"
}
],
"webinarID": 123456
},
{
...
}
]
}
views.py
class TeacherFeedbackViewSet(ViewSet):
permission_classes = [IsAuthenticated, TeacherFeedbackPerm]
renderer_classes = [CamelCaseJSONRenderer]
@base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
serializer = ModeratorFeedback(moderator)
return Response(serializer.data)
serializers.py
class TeacherFeedbackSerializerDetail(ModelSerializer):
created_at = DateTimeField(source='datetime_filled')
created_by = SerializerMethodField(method_name='get_created_by')
categories = SerializerMethodField(method_name='get_categories')
webinar_id = IntegerField(source='webinar.id')
moderator_id = IntegerField(source='moderator.id')
class Meta:
model = TeacherFeedback
fields = ['id', 'created_by', 'created_at', 'categories', 'score', 'comment', 'moderator_id', 'webinar_id']
def get_categories(self, feedback: TeacherFeedback):
data = []
category_names = list(FeedbackCategory.objects.all().values_list('name', flat=True))
for category in feedback.category.all():
z = TeacherFeedbackCategory.objects.get(category=category, feedback=feedback)
data.append({"name": z.category.name, "status": z.status})
unset = list(map(lambda x: {"name": x, "status": "unset"},
list(set(category_names) - set([i["name"] for i in data]))))
return sorted(data + unset, key=lambda x: x["status"])
def get_created_by(self, feedback: TeacherFeedback):
return str(feedback.created_by.teacher)
class ModeratorFeedback(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
feedback = TeacherFeedbackSerializerDetail(many=True, source='actual_feedbacks')
class Meta:
model = Moderator
fields = ['stats', 'feedback']
def get_stats_list(self, moderator: Moderator):
data = {}
for feedback in moderator.actual_feedbacks:
for category in feedback.category.all():
category_detail = TeacherFeedbackCategory.objects.get(feedback=feedback, category=category)
if category.name not in data:
data[category.name] = [category_detail.status]
else:
data[category.name].append(category_detail.status)
stats = []
for k, statuses in data.items():
weight = 100/len(statuses)
current_value = 0
for status in statuses:
if status == 'positive':
current_value += weight
else:
current_value -= weight
stats.append({"name": k, "value": float("{0:.2f}".format(current_value))})
return stats
这里为了实现分页,需要分别对stats
和feedback
数据做serializer
首先你可以定义 ModeratorStats
序列化器。
class ModeratorStats(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
class Meta:
model = Moderator
fields = ['stats']
def get_stats_list(self, moderator: Moderator):
...
而TeacherFeedbackSerializerDetail
序列化器用于反馈。
现在可见,
from django.core.paginator import Paginator
from rest_framework.response import Response
class TeacherFeedbackViewSet(ViewSet):
...
@base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
# first get page and size param
page = int(request.GET.get('page', "1"))
size = int(request.GET.get('size', "10"))
# here I assumed the foreign key field name is `moderator`
query_set = TeacherFeedback.objects.filter(moderator__id = pk)
paginator = Paginator(query_set.order_by('id'), size)
feedbacks = paginator.page(page)
stats_data = ModeratorStats(moderator).data
feedbacks = TeacherFeedbackSerializerDetail(feedbacks, many=True).data
return Response({"stats": stats_data, "feedback": feedbacks})
并且在前端,您需要上传分页参数,例如 ...?page=1&size=10
。
我有一项任务需要通过版主 ID 获取统计信息和反馈。 'stats' 字段是通用字段,'feedback' 字段是反馈列表。我可以为 'feedback' 字段分页吗?当然,我可以为统计数据和反馈设置不同的端点,但我不允许这样做。
// GET /api/moderators/:id/feedback
{
"stats": [
{
"name": "123",
"value": -10
}
],
"feedback": [
{
"id": 1,
"createdBy": "FN LN",
"createdAt": "DT",
"comment": "",
"score": 5,
"categories": [
{
"name": "123",
"status": "POSITIVE/NEGETIVE/UNSET"
}
],
"webinarID": 123456
},
{
...
}
]
}
views.py
class TeacherFeedbackViewSet(ViewSet):
permission_classes = [IsAuthenticated, TeacherFeedbackPerm]
renderer_classes = [CamelCaseJSONRenderer]
@base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
serializer = ModeratorFeedback(moderator)
return Response(serializer.data)
serializers.py
class TeacherFeedbackSerializerDetail(ModelSerializer):
created_at = DateTimeField(source='datetime_filled')
created_by = SerializerMethodField(method_name='get_created_by')
categories = SerializerMethodField(method_name='get_categories')
webinar_id = IntegerField(source='webinar.id')
moderator_id = IntegerField(source='moderator.id')
class Meta:
model = TeacherFeedback
fields = ['id', 'created_by', 'created_at', 'categories', 'score', 'comment', 'moderator_id', 'webinar_id']
def get_categories(self, feedback: TeacherFeedback):
data = []
category_names = list(FeedbackCategory.objects.all().values_list('name', flat=True))
for category in feedback.category.all():
z = TeacherFeedbackCategory.objects.get(category=category, feedback=feedback)
data.append({"name": z.category.name, "status": z.status})
unset = list(map(lambda x: {"name": x, "status": "unset"},
list(set(category_names) - set([i["name"] for i in data]))))
return sorted(data + unset, key=lambda x: x["status"])
def get_created_by(self, feedback: TeacherFeedback):
return str(feedback.created_by.teacher)
class ModeratorFeedback(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
feedback = TeacherFeedbackSerializerDetail(many=True, source='actual_feedbacks')
class Meta:
model = Moderator
fields = ['stats', 'feedback']
def get_stats_list(self, moderator: Moderator):
data = {}
for feedback in moderator.actual_feedbacks:
for category in feedback.category.all():
category_detail = TeacherFeedbackCategory.objects.get(feedback=feedback, category=category)
if category.name not in data:
data[category.name] = [category_detail.status]
else:
data[category.name].append(category_detail.status)
stats = []
for k, statuses in data.items():
weight = 100/len(statuses)
current_value = 0
for status in statuses:
if status == 'positive':
current_value += weight
else:
current_value -= weight
stats.append({"name": k, "value": float("{0:.2f}".format(current_value))})
return stats
这里为了实现分页,需要分别对stats
和feedback
数据做serializer
首先你可以定义 ModeratorStats
序列化器。
class ModeratorStats(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
class Meta:
model = Moderator
fields = ['stats']
def get_stats_list(self, moderator: Moderator):
...
而TeacherFeedbackSerializerDetail
序列化器用于反馈。
现在可见,
from django.core.paginator import Paginator
from rest_framework.response import Response
class TeacherFeedbackViewSet(ViewSet):
...
@base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
# first get page and size param
page = int(request.GET.get('page', "1"))
size = int(request.GET.get('size', "10"))
# here I assumed the foreign key field name is `moderator`
query_set = TeacherFeedback.objects.filter(moderator__id = pk)
paginator = Paginator(query_set.order_by('id'), size)
feedbacks = paginator.page(page)
stats_data = ModeratorStats(moderator).data
feedbacks = TeacherFeedbackSerializerDetail(feedbacks, many=True).data
return Response({"stats": stats_data, "feedback": feedbacks})
并且在前端,您需要上传分页参数,例如 ...?page=1&size=10
。