DRF 分页 #
一、分页概述 #
1.1 为什么需要分页 #
当数据量很大时,分页可以:
- 减少网络传输
- 提高响应速度
- 降低服务器负载
- 改善用户体验
1.2 分页类型 #
| 类型 | 说明 | 适用场景 |
|---|---|---|
| PageNumberPagination | 页码分页 | 传统分页 |
| LimitOffsetPagination | 偏移分页 | 灵活分页 |
| CursorPagination | 游标分页 | 大数据集 |
二、PageNumberPagination #
2.1 全局配置 #
python
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
2.2 自定义分页类 #
python
from rest_framework.pagination import PageNumberPagination
class StandardPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
page_query_param = 'page'
class LargePagination(PageNumberPagination):
page_size = 50
max_page_size = 200
2.3 视图中使用 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = StandardPagination
2.4 请求示例 #
text
GET /api/articles/?page=2
GET /api/articles/?page=2&page_size=20
2.5 响应格式 #
json
{
"count": 100,
"next": "http://api.example.com/articles/?page=3",
"previous": "http://api.example.com/articles/?page=1",
"results": [...]
}
三、LimitOffsetPagination #
3.1 配置 #
python
from rest_framework.pagination import LimitOffsetPagination
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 10
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 100
3.2 使用 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = CustomLimitOffsetPagination
3.3 请求示例 #
text
GET /api/articles/?limit=10&offset=20
GET /api/articles/?limit=5
3.4 响应格式 #
json
{
"count": 100,
"next": "http://api.example.com/articles/?limit=10&offset=30",
"previous": "http://api.example.com/articles/?limit=10&offset=10",
"results": [...]
}
四、CursorPagination #
4.1 配置 #
python
from rest_framework.pagination import CursorPagination
class ArticleCursorPagination(CursorPagination):
page_size = 20
cursor_query_param = 'cursor'
ordering = '-created_at'
4.2 使用 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = ArticleCursorPagination
4.3 请求示例 #
text
GET /api/articles/
GET /api/articles/?cursor=cD0yMDI0LTAxLTAx
4.4 响应格式 #
json
{
"next": "http://api.example.com/articles/?cursor=cD0yMDI0LTAxLTAx",
"previous": null,
"results": [...]
}
4.5 优势 #
- 不显示总数,性能更好
- 适合无限滚动
- 数据一致性更好
五、自定义分页 #
5.1 自定义响应格式 #
python
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomPagination(PageNumberPagination):
page_size = 10
def get_paginated_response(self, data):
return Response({
'success': True,
'data': data,
'pagination': {
'total': self.page.paginator.count,
'page': self.page.number,
'page_size': self.page_size,
'total_pages': self.page.paginator.num_pages,
'has_next': self.page.has_next(),
'has_previous': self.page.has_previous(),
}
})
5.2 全局配置 #
python
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'core.pagination.CustomPagination',
'PAGE_SIZE': 10,
}
5.3 响应格式 #
json
{
"success": true,
"data": [...],
"pagination": {
"total": 100,
"page": 1,
"page_size": 10,
"total_pages": 10,
"has_next": true,
"has_previous": false
}
}
六、禁用分页 #
6.1 视图级别 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = None
6.2 action级别 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@action(detail=False, pagination_class=None)
def all(self, request):
articles = self.get_queryset()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
七、分页最佳实践 #
7.1 选择合适的分页类型 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_pagination_class(self):
if self.action == 'list':
return StandardPagination
elif self.action == 'timeline':
return CursorPagination
return None
7.2 优化查询 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.select_related(
'author', 'category'
).prefetch_related(
'tags'
).only(
'id', 'title', 'summary', 'created_at'
)
serializer_class = ArticleSerializer
7.3 缓存计数 #
python
from django.core.cache import cache
class CachedPagination(PageNumberPagination):
def get_count(self, queryset):
cache_key = f'article_count_{queryset.query}'
count = cache.get(cache_key)
if count is None:
count = super().get_count(queryset)
cache.set(cache_key, count, 60 * 5)
return count
八、总结 #
本章学习了DRF分页:
- PageNumberPagination:传统页码分页
- LimitOffsetPagination:偏移分页
- CursorPagination:游标分页
- 自定义分页:自定义响应格式
- 最佳实践:选择和优化
让我们继续学习过滤与排序!
最后更新:2026-03-28