Django中Datatable加载5万+行数据卡顿 求服务端处理完整实现方案
完整实现方案
你当前卡顿的核心原因是一次性查询全量5万+数据渲染到HTML,前端Datatable在客户端做分页、排序、搜索,需要一次性处理数万条DOM节点和数据,必然卡顿。服务端处理模式就是把分页、排序、搜索逻辑全部移到后端执行,每次仅返回当前页需要的少量数据,从根本上解决性能问题。
步骤1:新增API路由
在你的app对应的urls.py中新增数据接口路由:
from django.urls import path from . import views urlpatterns = [ # 原有路由保留 path('party-list/', views.party_list, name='party_list'), # 新增Datatable服务端接口 path('party-list-ajax/', views.party_list_ajax, name='party_list_ajax'), ]
步骤2:编写服务端处理视图
在views.py中新增接口逻辑,处理Datatable的分页、排序、搜索请求:
from django.http import JsonResponse from django.db.models import Q from .models import PartyMaster def party_list(request): # 不再查询全量数据,仅渲染模板 return render(request,'party_master/party_edit.html') def party_list_ajax(request): # 接收Datatable固定参数 draw = int(request.GET.get('draw', 1)) start = int(request.GET.get('start', 0)) length = int(request.GET.get('length', 50)) search_value = request.GET.get('search[value]', '').strip() order_column = int(request.GET.get('order[0][column]', 0)) order_dir = request.GET.get('order[0][dir]', 'asc') # 列映射,防止SQL注入,对应表格的列顺序 columns_map = { 0: 'party_name', 1: 'email', 2: 'contact', 3: 'country', 4: 'sub_country__country_category' } order_field = columns_map.get(order_column, 'party_name') if order_dir == 'desc': order_field = f'-{order_field}' # 基础查询集,用select_related解决外键N+1查询问题 queryset = PartyMaster.objects.select_related('sub_country').all() # 处理搜索逻辑 if search_value: queryset = queryset.filter( Q(party_name__icontains=search_value) | Q(email__icontains=search_value) | Q(contact__icontains=search_value) | Q(country__icontains=search_value) | Q(sub_country__country_category__icontains=search_value) ) # 统计总数 total_count = PartyMaster.objects.count() filtered_count = queryset.count() # 分页查询 queryset = queryset.order_by(order_field)[start:start+length] # 组装返回数据 data = [] for party in queryset: data.append([ party.party_name, party.email, party.contact, party.country, party.sub_country.country_category if party.sub_country else '' ]) # 返回符合Datatable要求的JSON格式 return JsonResponse({ 'draw': draw, 'recordsTotal': total_count, 'recordsFiltered': filtered_count, 'data': data })
步骤3:修改模板代码
首先删除tbody内的循环渲染代码,然后修改Datatable初始化配置,注意调整JS引入顺序(必须先引入jQuery再引入Datatable):
{% extends 'base.html' %} {% block title %} Party List's {% endblock %} {% block body %} <div class="container"> <a href="{% url 'add_party' %}" class="btn btn-primary button_class mt-5">Party Master Form</a> <div class="py-3"> <div class="table-responsive"> <table class="table table-striped table-hover text-center table-responsive-sm" id="party_table"> <thead class="table-head"> <tr> <th scope="col">Party Name</th> <th scope="col">Email</th> <th scope="col">Contact</th> <th scope="col">Country</th> <th scope="col">Sub Country</th> </tr> </thead> <!-- tbody留空,数据通过AJAX加载 --> <tbody> </tbody> </table> </div> </div> </div> {% endblock %} {% block js %} <!-- 注意引入顺序:先引入jQuery,再引入Datatable相关资源 --> <script src="https://code.jquery.com/jquery-3.5.1.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.25/css/jquery.dataTables.css"> <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.1/js/dataTables.buttons.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.1/js/buttons.html5.min.js"></script> <script src="https://cdn.datatables.net/buttons/1.7.1/js/buttons.print.min.js"></script> <script> $(document).ready(function() { $('#party_table').DataTable( { dom: 'Bfrtip', "pageLength": 50, // 开启服务端处理模式 processing: true, serverSide: true, // 配置接口地址 ajax: "{% url 'party_list_ajax' %}", buttons: [ { extend: 'excelHtml5', exportOptions: { columns: [ 0, 1, 2, 3, 4 ] } }, { extend: 'pdfHtml5', exportOptions: { columns: [ 0, 1, 2, 3, 4 ] } }, ] } ); } ); </script> {% endblock %}
替代解决方案
如果暂时不想改动后端逻辑,也可以选择以下优化方案:
- 开启Datatable延迟渲染:在Datatable配置中加
deferRender: true,只会渲染当前页的DOM节点,能大幅降低首次加载压力,5万条数据场景下可以做到基本流畅,但性能上限还是低于服务端处理模式。 - 更换前端表格组件:使用ag-Grid、Tabulator等专门针对大数据优化的前端表格组件,客户端处理10万条以内数据的性能明显优于旧版Datatable。
- 虚拟滚动:搭配前端表格的虚拟滚动功能,仅渲染可视区域内的行,不管总数据量多少都不会卡顿。
优化注意点
- 给常用搜索、排序字段加数据库索引:在
PartyMaster模型的party_name、email、contact等字段上添加db_index=True,可以大幅提升搜索排序速度。 - 全量导出优化:如果需要导出全量5万+数据,不要用前端导出功能,建议单独做后端导出接口,避免前端处理大量数据卡顿。
- 接口缓存:如果数据更新频率不高,可以给
party_list_ajax接口加缓存,进一步提升响应速度。
内容的提问来源于stack exchange,提问作者Pulkit Arora
相关产品推荐
相关产品推荐

