Datatables.net结合DRF实现服务端处理时分页无法正常跳转问题
问题核心原因
Datatables服务端模式默认发送start(当前页偏移量)、length(每页条数)格式的分页参数,同时携带大量列、排序、搜索类冗余参数,而DRF默认分页器仅识别page(页码)、page_size(每页条数)格式的参数,参数格式不匹配导致DRF无法正确解析分页请求,永远返回第一页数据。
完整解决方案
前端配置优化
保留你已有的响应映射逻辑,新增请求参数转换逻辑,过滤冗余参数、适配DRF的参数格式即可,示例配置如下:
$('#你的表格ID').DataTable({ serverSide: true, processing: true, // 加载中提示,可选 ajax: { url: "你的DRF接口地址", type: "GET", // 自定义请求参数,适配DRF格式 data: function (d) { // 删掉Datatables默认的冗余列参数,不需要搜索/排序功能可直接清空 delete d.columns; delete d.order; delete d.search; // 转换为DRF默认分页器识别的参数 d.page_size = d.length; d.page = (d.start / d.length) + 1; // 若需要保留搜索/排序功能,放开下方注释做参数转换即可 // if(d.order.length) d.ordering = `${d.order[0].dir === 'desc' ? '-' : ''}${d.columns[d.order[0].column].data}` // if(d.search.value) d.search = d.search.value return d; }, // 你原有响应映射逻辑保留 dataFilter: function (res) { res = JSON.parse(res); return JSON.stringify({ recordsTotal: res.count, recordsFiltered: res.count, data: res.results }) } }, // 其余你的列配置、样式配置保留即可 columns: [ // 你的列定义 ] })
后端DRF配置适配
方案1:使用默认分页器(推荐)
直接复用DRF自带的PageNumberPagination,配置对应参数名即可:
from rest_framework.pagination import PageNumberPagination from rest_framework.viewsets import ModelViewSet from .models import 你的业务模型 from .serializers import 你的业务序列化器 # 自定义分页规则 class CustomPagination(PageNumberPagination): page_size_query_param = 'page_size' # 匹配前端传的page_size参数 max_page_size = 100 # 限制最大每页条数,防止恶意请求 # 你的业务视图 class YourBusinessViewSet(ModelViewSet): queryset = 你的业务模型.objects.all() serializer_class = 你的业务序列化器 pagination_class = CustomPagination # 若需要支持搜索、排序功能,放开下方配置即可 # filter_backends = [SearchFilter, OrderingFilter] # search_fields = ['字段1', '字段2'] # 允许搜索的字段 # ordering_fields = ['字段1', '字段2'] # 允许排序的字段
方案2:自定义Datatables专用分页器
如果你不想修改前端参数,要直接解析Datatables原生的start、length参数,可以自定义分页器:
from rest_framework.pagination import BasePagination from rest_framework.response import Response class DatatablesPagination(BasePagination): def paginate_queryset(self, queryset, request, view=None): self.start = int(request.query_params.get('start', 0)) self.length = int(request.query_params.get('length', 10)) self.total = queryset.count() return list(queryset[self.start:self.start+self.length]) def get_paginated_response(self, data): return Response({ 'count': self.total, 'next': None, 'previous': None, 'results': data })
在视图中把pagination_class替换为DatatablesPagination即可使用。
验证排查点
- 点击分页按钮时打开浏览器控制台Network面板,确认请求参数中的
page/page_size值随页码切换正常变化 - 确认DRF返回的
count字段为总数据条数,results长度和page_size一致 - 若出现分页页码显示错误,检查前端
dataFilter中recordsTotal和recordsFiltered是否都赋值为接口返回的count,两个值不一致会导致Datatables分页计算异常
内容的提问来源于stack exchange,提问作者Andre Garcia
相关产品推荐
相关产品推荐

