DjangoRestFramework框架三种分页功能的实现 - 在DjangoStarter项目模板中封装
前言 继续Django后端开发系列文章。刚好遇到一个分页的需求,就记录一下。 Django作为一个“全家桶”型的框架,本身啥都有,分页组件也是有的,但默认的分页组件没有对API开发做优化,所以DjangoRestFramework这个专门写API的框架又把Django的分页组件包装了一层,集成在viewsets里的时候会更方便。 不过我们不可能一直用viewsets,有一部分API还是要用自由度更
目录7 个章节
前言
继续Django后端开发系列文章。刚好遇到一个分页的需求,就记录一下。
Django作为一个“全家桶”型的框架,本身啥都有,分页组件也是有的,但默认的分页组件没有对API开发做优化,所以DjangoRestFramework这个专门写API的框架又把Django的分页组件包装了一层,集成在viewsets里的时候会更方便。
不过我们不可能一直用viewsets,有一部分API还是要用自由度更高的ApiView的,但ApiView里又没办法直接使用默认的分页组件,这时我们就需要封装一下。
并且DjangoRestFramework默认的分页信息也不够全,比如没有总页数,这点我们也可以在封装的时候魔改一下。
DRF中的分页方式
DRF中为我们封装了三种分页方式,分别是:
PageNumberPagination:顾名思义,不解释LimitOffsetPagination:Offset分页CursorPagination:加密分页
本文打算只介绍最常用的第一种,后面两种同时也会做封装,但篇幅关系就不介绍了,有兴趣的同学可以尝试使用一下。
开始代码
首先还是在我们的「DjangoStarter」项目中,在utils目录下新建一个名为paginator的Python Package。
因为代码不多,我们直接写在utils/paginator/__init__.py文件下就好。
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' # 重写要排序的字段
针对前面说的“DjangoRestFramework默认的分页信息也不够全”问题,我重写了get_paginated_response方法,在返回值中加入这几个参数
page_count:总页数page_number:当前页码page_size:每页数量
然后另外两个参数也改了名字,更直观,更符合我们平时的开发习惯。
...
这样就完成了封装,我们接下来在代码里测试一下
测试接口
来写个测试接口看看效果
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)
})
配置一下路由
urlpatterns = [
path('test_page', views.test_page),
]
测试效果
写完的接口接受两个参数,page和page_size,我在@swagger_auto_schema装饰器里声明了这两个参数,方便我们在Swagger文档中做测试。
我们设定page_size=5,拿到的JSON数据是这样的:
{
"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
]
}
}
}
效果不错,很清晰。
收工。
在ViewSet中使用
当然,这个封装好的分页组件在ViewSet里也可以使用
比如说直接配置
from utils.paginator import NumberPaginator
class TestViewSet(viewsets.ReadOnlyModelViewSet):
# ...
pagination_class = NumberPaginator
也可以全局配置
编辑settings.py文件,修改RestFramework的配置
DjangoStarter做了
settings.py拆分,RestFramework的配置在config/rest_framework.py文件里
REST_FRAMEWORK = {
# 设置分页(使用DjangoStarter封装的分页器)
'DEFAULT_PAGINATION_CLASS': 'utils.paginator.NumberPaginator'
}
参考资料
_EOF_
DjangoRestFramework框架三种分页功能的实现 - 在DjangoStarter项目模板中封装
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Django-Filter介绍与刁钻需求的实现方法
Django-Filter是一个非常好用的第三方库,很好的利用了Django ORM的特性,可以使用很少的代码就扩展原有的接口,实现多种筛选功能~ 场景 Model定义的部分代码,可以看到需求模型包括了 关键词 keyword、区域 region、需求状态 require_status,这三个字段 class Require(models.Model): 需求 keyword =
2021-12-18 · Django · 约 1 分钟
Django-Import-Export插件控制数据导入流程
前言 之前写过两篇跟这个插件有关的文章,可以回顾一下: Django数据导入导出神器django-import-export使用 Django-Import-Export插件关于外键的处理 最近有个朋友留言问我一个关于django-import-export插件的问题 为了形象表达这个问题,我举个书籍管理的例子来描述一下 数据库表 | id | name | price | | ---- |
2022-09-02 · Django · 约 1 分钟
Django应用部署:uwsgi+Nginx方式
环境准备 nginx+uwsgi方式部署顾名思义,需要nginx和uwsgi两个软件包。 nginx不用说,是必备的,关于nginx的安装本文不再赘述,详情可以自行搜索或者参考我以前的文章: Debian8搭建LEMP环境 安装uwsgi pip install uwsgi 上传项目代码 & 测试 # 进入项目目录,具体目录请自行选择 cd /path/to/project # 建立虚拟环境 v
2022-04-02 · Django · 约 1 分钟
给Django-Admin添加验证码和多次登录尝试限制
Django自带的Admin很好用,但是放到生产环境总还差了点什么= = 看看admin的介绍: Django奉行Python的内置电池哲学。它自带了一系列在Web开发中用于解决常见问题或需求的额外的、可选工具。这些工具和插件,例如django.contrib.redirects都必须在settings中的INSTALLED_APPS处进行注册,有的还需要执行manage.py migrate命令
2021-12-18 · Django · 约 1 分钟
讨论
共 0 条加载评论中…