Implementing Three Pagination Features of Django REST Framework - Encapsulated in the DjangoStarter Project Template
Preface Continuing the Django backend development series. I happened to run into a pagination requirement, so I'll document it here. Django, as an "all-in-one" framework, has everything built in, including a pagination component. However, the default pagination component isn't optimized for API development, so Django REST Framework, which is specifically for writing APIs, wraps Django's pagination component another layer, making it more convenient when integrated into viewsets. However, we can't always use viewsets; some APIs still need the more flexible
目录7 个章节
Preface
Continuing the Django backend development series. I happened to run into a pagination requirement, so I'll document it here.
Django, as an "all-in-one" framework, has everything built in, including a pagination component. However, the default pagination component isn't optimized for API development, so Django REST Framework, which is specifically for writing APIs, wraps Django's pagination component another layer, making it more convenient when integrated into viewsets.
However, we can't always use viewsets; some APIs still need the more flexible ApiView, but ApiView can't directly use the default pagination component, so we need to wrap it ourselves.
Moreover, Django REST Framework's default pagination info isn't complete enough—for example, it doesn't include the total number of pages. We can also hack this a bit when wrapping it.
Pagination Methods in DRF
DRF provides three pagination methods for us:
PageNumberPagination: As the name suggests, no explanation neededLimitOffsetPagination: Offset paginationCursorPagination: Encrypted pagination
This article will only introduce the first, most commonly used one. The other two will also be wrapped, but due to space constraints I won't cover them. Interested readers can give them a try.
Let's Start Coding
First, in our DjangoStarter project, create a Python package named paginator under the utils directory.
Since there isn't much code, we can just write it in the utils/paginator/__init__.py file.
from collections import OrderedDict
from django.core.paginator import Paginator
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
from rest_framework.response import Response
class NumberPaginator(PageNumberPagination):
"""页码分页"""
def __init__(
self,
page_size,
page_size_query_param='page_size',
page_query_param='page',
max_page_size=None
):
"""
初始化分页
:param page_size: 每页显示多少条
:param page_size_query_param: URL中每页显示条数的参数
:param page_query_param: URL中页码的参数
:param max_page_size: 最大页码数限制
"""
self.page_size = page_size
self.page_size_query_param = page_size_query_param
self.page_query_param = page_query_param
self.max_page_size = max_page_size
def get_paginated_response(self, data):
paginator: Paginator = self.page.paginator
return Response(OrderedDict([
('total_item_count', paginator.count),
('page_count', paginator.num_pages),
('page_number', self.page.number),
('page_size', self.page_size),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
class LimitOffsetPaginator(LimitOffsetPagination):
"""Offset分页"""
default_limit = 1
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 999
class CursorPaginator(CursorPagination):
"""加密分页"""
cursor_query_param = 'cursor'
page_size = 1
ordering = '-id' # 重写要排序的字段
To address the earlier issue that "Django REST Framework's default pagination info isn't complete enough", I overrode the get_paginated_response method and added these fields to the response:
page_count: total number of pagespage_number: current page numberpage_size: items per page
I also renamed the other two fields to make them more intuitive and more consistent with our usual development habits.
...
That completes the wrapping. Next, let's test it in code.
Test Endpoint
Let's write a test endpoint to see how it works
from utils.paginator import NumberPaginator
@swagger_auto_schema(
method='get', operation_summary='测试分页功能',
manual_parameters=[
openapi.Parameter('page', openapi.IN_QUERY, type=openapi.TYPE_NUMBER),
openapi.Parameter('page_size', openapi.IN_QUERY, type=openapi.TYPE_NUMBER),
])
@api_view()
def test_page(request):
# 测试数据
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
paginator = NumberPaginator(request.query_params.get('page_size', 10))
return paginator.get_paginated_response({
'data': paginator.paginate_queryset(queryset=data, request=request)
})
Configure the route
urlpatterns = [
path('test_page', views.test_page),
]
Test Results
The finished endpoint accepts two parameters, page and page_size. I declared these two parameters in the @swagger_auto_schema decorator so we can test them conveniently in the Swagger docs.
We set page_size=5, and the JSON data we get looks like this:
{
"message": "请求成功",
"code": 200,
"data": {
"total_item_count": 10,
"page_count": 2,
"page_number": 1,
"page_size": "5",
"next": "http://127.0.0.1:8005/core/test_page?page=2&page_size=5",
"previous": null,
"results": {
"data": [
1,
2,
3,
4,
5
]
}
}
}
Looks good, very clear.
That's a wrap.
Using It in a ViewSet
Of course, this wrapped pagination component can also be used in a ViewSet
For example, configure it directly
from utils.paginator import NumberPaginator
class TestViewSet(viewsets.ReadOnlyModelViewSet):
# ...
pagination_class = NumberPaginator
You can also configure it globally
Edit the settings.py file and modify the REST Framework configuration
DjangoStarter splits
settings.py; the REST Framework configuration is in theconfig/rest_framework.pyfile
REST_FRAMEWORK = {
# 设置分页(使用DjangoStarter封装的分页器)
'DEFAULT_PAGINATION_CLASS': 'utils.paginator.NumberPaginator'
}
References
_EOF_
Implementing Three Pagination Features of Django REST Framework - Encapsulated in the DjangoStarter Project Template
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Django+Logging:日志记录配置与使用方法
前言 日志在程序开发中是少不了的,通过日志我们可以分析到错误在什么地方,有什么异常。在生产环境下有很大的用途。在Java开发中通常用log4j,logback等第三方组件。那么在django中是怎么处理日志?django利用的就是Python提供的logging模块,但django中要用logging,还得有一定的配置规则,需要在setting中设置。 Logging模块 Logging模块为应用
2022-04-02 · Django · 约 1 分钟
轻松搞定Django分页功能
view代码 from django.core.paginator import Paginator def announcement(request): ctx = { 'global': GlobalCtx, 'announcements': models.Announcement.objects.all(), } paginator
2022-05-27 · Django · 约 1 分钟
一小时完成后台开发:DjangoRestFramework开发实践
DjangoRestFramework开发实践 在这之前我写过一篇关于Django与Drf快速开发实践的博客,Django快速开发实践:Drf框架和xadmin配置指北,粗略说了一下Drf配置和基本使用,不过里面只是涉及到最基本的CRUD,在正常的后端开发中涉及的诸如认证和权限、消息队列、缓存之类的操作,上一篇博客并没有涉及,这次开发我仔细了看了官方文档的这几个部分,把这部分的功能完善了起来。 D
2021-12-18 · Django · 约 1 分钟
Django全文检索实现:HayStack-+-Whoosh-+-Jieba
涉及到的工具 haystack是django的开源搜索框架,该框架支持**Solr**, Elasticsearch, Whoosh, **Xapian搜索引擎,不用更改代码,直接切换引擎,减少代码量。 搜索引擎使用Whoosh,这是一个由纯Python实现的全文搜索引擎,没有二进制文件等,比较小巧,配置比较简单,当然性能自然略低。 中文分词Jieba,由于Whoosh自带的是英文分词,对中文的分
2022-08-26 · Django · 约 1 分钟
讨论
共 0 条加载评论中…