如何让DRF适配bootstrap-table自定义query_params实现排序筛选与分页?
适配Bootstrap-Table的DRF服务端分页与排序实现
一、核心思路:解析Bootstrap-Table的请求参数
Bootstrap-Table发送的请求参数包含:
- 分页:
offset(起始位置)、limit(每页条数) - 排序:单列用
sort(字段名)+order(排序方向);多列用multiSort数组(每个元素含sortName和sortOrder)
DRF默认的分页(PageNumberPagination)和排序(OrderingFilter)不匹配这些参数,我们可以通过自定义分页类和手动解析排序参数来适配。
二、具体实现步骤
1. 自定义分页类适配Offset/Limit
DRF默认按页码分页,我们需要自定义支持偏移量的分页类:
from rest_framework.pagination import BasePagination from rest_framework.response import Response class BootstrapTablePagination(BasePagination): def paginate_queryset(self, queryset, request, view=None): self.offset = int(request.query_params.get('offset', 0)) self.limit = int(request.query_params.get('limit', 25)) self.total = queryset.count() return queryset[self.offset:self.offset+self.limit] def get_paginated_response(self, data): return Response({ 'total': self.total, 'totalNotFiltered': self.total, # 若有搜索过滤,需改为过滤前的总数 'rows': data })
2. 在视图中解析排序参数
在get_queryset方法里手动处理Bootstrap-Table的排序参数,构建DRF支持的排序规则:
from rest_framework import generics from .models import Parcels from .serializers import ParcelSerializer class ParcelViewSet(generics.ListAPIView): serializer_class = ParcelSerializer pagination_class = BootstrapTablePagination # 绑定自定义分页 def get_queryset(self): queryset = Parcels.objects.all() request = self.request ordering = [] # 处理单列排序 sort_field = request.query_params.get('sort') sort_order = request.query_params.get('order', 'asc') if sort_field: ordering.append(f'-{sort_field}' if sort_order == 'desc' else sort_field) # 处理多列排序(解析嵌套的multiSort参数) query_params_dict = request.query_params.dict() multi_sort_entries = [] for key, value in query_params_dict.items(): if key.startswith('multiSort[') and 'sortName' in key: idx = key.split('[')[1].split(']')[0] sort_name = value sort_order = query_params_dict.get(f'multiSort[{idx}][sortOrder]', 'asc') multi_sort_entries.append((sort_name, sort_order)) # 合并多列排序规则 for sort_name, sort_order in multi_sort_entries: ordering.append(f'-{sort_name}' if sort_order == 'desc' else sort_name) # 应用排序规则 if ordering: queryset = queryset.order_by(*ordering) return queryset # 注释原list方法,由分页类自动生成符合Bootstrap-Table格式的响应 # def list(self, request, *args, **kwargs): # ...
3. 序列化器保持不变
你的ParcelSerializer无需修改:
from rest_framework import serializers from .models import Parcels class ParcelSerializer(serializers.ModelSerializer): class Meta: model = Parcels fields = '__all__'
三、方案对比与选择
1. 改DRF(当前方案)
- 优点:完全满足你积累DRF经验的需求,能深入理解DRF分页、排序的底层逻辑
- 缺点:需手动处理参数解析,后续若Bootstrap-Table参数格式变化,需同步修改代码,维护成本略高
2. 改Bootstrap-Table请求参数(生产环境更优)
- 实现思路:通过Bootstrap-Table的
queryParams钩子,将sort/order/multiSort转换为DRF默认的ordering参数 - 前端示例代码:
$('#your-table-id').bootstrapTable({ // 其他配置... queryParams: function(params) { let ordering = []; // 处理单列排序 if (params.sort) { ordering.push(params.order === 'desc' ? '-' + params.sort : params.sort); } // 处理多列排序 if (params.multiSort?.length) { params.multiSort.forEach(item => { ordering.push(item.sortOrder === 'desc' ? '-' + item.sortName : item.sortName); }); } // 替换为DRF的ordering参数 params.ordering = ordering.join(','); // 删除原排序参数 delete params.sort; delete params.order; delete params.multiSort; return params; } });
- 优点:遵循DRF的REST规范,代码更简洁,后续维护成本低,是生产环境的推荐方案
- 缺点:无法达到你积累DRF经验的目的
总结
如果核心目标是学习DRF自定义扩展,选择改DRF的方案;如果是生产环境稳定使用,优先选择改Bootstrap-Table参数的方案。
内容的提问来源于stack exchange,提问作者Danza
相关产品推荐
相关产品推荐

