Django Rest Framework:在 ViewSet 上打开分页(如 ModelViewSet 分页)
Posted
技术标签:
【中文标题】Django Rest Framework:在 ViewSet 上打开分页(如 ModelViewSet 分页)【英文标题】:Django Rest Framework: turn on pagination on a ViewSet (like ModelViewSet pagination) 【发布时间】:2015-10-25 11:33:54 【问题描述】:我有一个这样的 ViewSet 来列出用户的数据:
class Foo(viewsets.ViewSet):
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
我想像 ModelViewSet 的默认分页一样打开分页:
"count": 55,
"next": "http://myUrl/?page=2",
"previous": null,
"results": [...,...,...,...]
The official doc 说:
只有在您使用通用视图或视图集时才会自动执行分页
...但是我的结果集根本没有分页。如何分页?
【问题讨论】:
这是来自类似 Stack Overflow 问题的非常 simple answer。 【参考方案1】:这种方式也适用于 Django Rest apiViews Api 的
from rest_framework.pagination import PageNumberPagination
class FooList(APIView):
page_size = 10
def get(self, request):
foo = Foo.objects.all()
paginator = PageNumberPagination()
paginator.page_size = page_size
result_page = paginator.paginate_queryset(foo, request)
serializer = FooSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
【讨论】:
【参考方案2】:在DRF中使用viewsets
和list
进行分页。
这里我处理了一个异常如果 page 是 empty 它将显示 empty 记录。
在设置定义页面大小时,这个页面大小是全局的并且被paginator_queryset
在视图中使用。
REST_FRAMEWORK = 'PAGE_SIZE': 10,
在 view.py 中:
from rest_framework import mixins, viewsets
class SittingViewSet(viewsets.GenericViewSet,
mixins.ListModelMixin):
serializer_class = SittingSerializer
queryset = Sitting.objects.all()
serializer = serializer_class(queryset, many=True)
def list(self, request, *args, **kwargs):
queryset =self.filter_queryset(Sitting.objects.all().order_by('id'))
page = request.GET.get('page')
try:
page = self.paginate_queryset(queryset)
except Exception as e:
page = []
data = page
return Response(
"status": status.HTTP_200_OK,
"message": 'No more record.',
"data" : data
)
if page is not None:
serializer = self.get_serializer(page, many=True)
data = serializer.data
return self.get_paginated_response(data)
# serializer = self.get_serializer(queryset, many=True)
return Response(
"status": status.HTTP_200_OK,
"message": 'Sitting records.',
"data" : data
)
注意:如果您不使用Order_by
,它将显示exception
,因为此列表
给出无序列表。
【讨论】:
你也可以访问***.com/a/46173281/8231158我给出了两个答案一个敌人视图集,另一个是API视图。 queryset = Sitting.objects.all() ,获取所有记录然后根据它进行分页是不是错了?如果有数百万条记录,会不会影响性能? Sitting.objects.all() 这是一个示例@Sandhu 根据您的要求您可以过滤记录,您可以根据您的要求编写自己的查询 您应该返回带有空列表的200 OK
,因为服务中确实存在 URL 和集合,但没有一个与查询参数匹配。检查***.com/questions/13366730
感谢@JPVentura,已更新【参考方案3】:
如果您想为特定的ViewSet
分页,但不需要自定义页面大小,则this answer 的一个稍微简单的变体:
REST_FRAMEWORK =
'PAGE_SIZE': 100
class FooViewSet(viewsets.ModelViewSet):
pagination_class = PageNumberPagination
【讨论】:
【参考方案4】:对于那些使用 DRF 3.1 或更高版本的用户,他们正在更改处理分页的默认方式。详情请见http://www.django-rest-framework.org/topics/3.1-announcement/。
现在,如果您想为 ModelViewSet 启用分页,您可以通过在 settings.py 文件中进行设置来全局执行此操作:
REST_FRAMEWORK =
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
或者,如果您只希望它用于一个 ModelViewSet,您可以手动为该视图集设置 pagination_class。
from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
class FooViewSet(viewsets.ModelViewSet):
pagination_class = StandardResultsSetPagination
这还允许您调整仅针对该视图集处理分页的方式。
DRF 3.1 还引入了可以使用的新类型的默认分页方案,例如 LimitOffset 和 Cursor。
【讨论】:
如果您使用 PageNumberPagination 请求 page1,然后将一个新项目添加到列表中,然后您再请求 page2,则您刚刚在 page1 中获得的最后一个项目将再次显示为第一个page2 中的项目(连续显示 2 次)。 CursorPagination 是比 PageNumberPagination 更推荐的方式。 CursorPagination 保持对对象的引用,不必为每个页面计算内容。实施见***.com/a/47657610/5881884【参考方案5】:尝试提供类变量
paginate_by = 10 #This will paginate by 10 results per page.
创建一个自定义 ViewSet
,它只执行 list
操作,作为您目前的情况。
class ListModelViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
pass
现在用这个定制的视图继承你的类Foo
class Foo(ListModelViewSet):
paginate_by = 10
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
这应该可以帮助您使分页正常工作。
【讨论】:
我添加了paginate_by = 10
,但它不起作用。如果我将class Foo(viewsets.ViewSet):
更改为class Foo(generics.ListCreateAPIView):
,我会收到此错误:as_view() 仅采用 1 个参数(给定 3 个)
您是否将任何参数传递给 .as_view()?其次,你为什么不使用ModelViewSet
?
不,与 .as_views() 无关。我没有使用ModelViewSet
,因为我需要编写一些逻辑来过滤我的queryset
的子集并将一些数据添加到与用户模型无关的结果集中(我的问题代码中省略了该逻辑)跨度>
查看此链接:django-rest-framework.org/api-guide/viewsets/…
还是不行 :( PS:你为什么用MongoGenericViewSet
?我用viewsets.GenericViewSet
代替...【参考方案6】:
只有在您使用泛型时才会自动执行分页 视图或视图集
第一个障碍是将文档翻译成英文。他们想要传达的是你想要一个通用的视图集。通用视图集从 generic ApiViews 扩展而来,它具有用于对查询集和响应进行分页的额外类方法。
另外,您提供了自己的list
方法,但默认分页过程实际上由mixin 处理:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
简单的解决方案,使用框架代码:
class Foo(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = User.objects.all()
serializer = UserSerializer
更复杂的解决方案是,如果您需要自定义 list
方法,那么您应该按照您认为合适的方式编写它,但采用上述混合代码 sn-p 的样式。
【讨论】:
以上是关于Django Rest Framework:在 ViewSet 上打开分页(如 ModelViewSet 分页)的主要内容,如果未能解决你的问题,请参考以下文章
Django中rest_framework的认证组件,权限组件,频率组件,序列化组件的最简化版接口
如何在 django-rest-framework 中为 API 使用 TokenAuthentication