大数据集下DataTables渲染过慢,求AJAX+deferRender实现指导
嘿,我来帮你搞定这个DataTables加载慢的问题!3000+条记录一次性渲染确实会把浏览器卡得够呛,AJAX服务器端分页+deferRender绝对是解决这个问题的最优方案,下面一步步给你讲怎么改造现有代码:
第一步:重构后端视图,支持AJAX分页查询
原来的视图是一次性把所有数据传给前端,现在我们要改成仅返回当前页需要的数据,同时支持搜索、排序这些DataTables的常用功能。
先修改你的views.py,新增一个处理AJAX请求的视图:
from django.http import JsonResponse from django.db.models import Q from .models import Client # 负责返回页面(不再需要传clients数据) def index(request): return render(request, 'app/index.html') # 处理DataTables的AJAX请求,返回分页后的JSON数据 def datatable_data(request): # 解析DataTables发送的请求参数 draw = int(request.GET.get('draw', 1)) start = int(request.GET.get('start', 0)) length = int(request.GET.get('length', 10)) search_value = request.GET.get('search[value]', '') column_index = int(request.GET.get('order[0][column]', 0)) order_dir = request.GET.get('order[0][dir]', 'asc') # 基础查询集,保留预取关联数据优化查询性能 queryset = Client.objects.all().prefetch_related('loan_set', 'loan_set__case_set') # 处理搜索过滤(根据你的表头,搜索姓名和锁定人) if search_value: queryset = queryset.filter( Q(firstName__icontains=search_value) | Q(lastName__icontains=search_value) | Q(lockedBy__icontains=search_value) ) # 处理排序 sort_columns = ['firstName', 'lastName'] # 对应表头的两列,第二列是操作列不支持排序 if column_index < len(sort_columns): sort_field = sort_columns[column_index] if order_dir == 'desc': sort_field = f'-{sort_field}' queryset = queryset.order_by(sort_field) # 统计总记录数和过滤后的记录数 total_records = Client.objects.count() filtered_records = queryset.count() # 分页截取数据 paginated_clients = queryset[start:start+length] # 构造要返回的行数据(把HTML逻辑从前端移到后端) data = [] csrf_token = request.META.get('CSRF_COOKIE', '') # 获取CSRF token用于表单 for c in paginated_clients: # 生成操作列的HTML if c.editLock: edit_html = f'<i class="fas fa-lock fa-lg" style="color:Red" title="W edycji przez: {c.lockedBy}"></i> {c.lockedBy}' else: edit_html = f'''<form method="post"> <input type="hidden" name="csrfmiddlewaretoken" value="{csrf_token}"> <a href="/edit/{c.pk}" name="c_id"><i class="fas fa-pen-square fa-2x" style="color:green"></i></a> </form>''' data.append([ f'{c.firstName} {c.lastName}', edit_html ]) # 返回符合DataTables要求的JSON格式 return JsonResponse({ 'draw': draw, 'recordsTotal': total_records, 'recordsFiltered': filtered_records, 'data': data })
然后在你的urls.py里添加这个视图的路由:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), path('datatable-data/', views.datatable_data, name='datatable_data'), ]
第二步:修改前端模板,用AJAX加载数据
原来的模板是用Django模板循环生成所有行,现在要改成空的表格,让DataTables通过AJAX从后端拉取数据:
<table id="case_list" class="display"> <thead> <tr> <td>Imię i nazwisko</td> <td>Edycja</td> </tr> </thead> <tbody> <!-- 这里留空,数据将由AJAX动态加载 --> </tbody> </table> <script type="text/javascript"> $(document).ready(function(){ $('#case_list').DataTable({ deferRender: true, // 延迟渲染非当前页的行,进一步提升性能 serverSide: true, // 开启服务器端处理(分页、过滤、排序都交给后端) ajax: '{% url "datatable_data" %}', // 对应我们新增的后端路由 columns: [ { data: 0 }, // 对应后端返回data数组的第一个元素(姓名) { data: 1, orderable: false } // 对应操作列,设置为不可排序 ], pageLength: 10, // 默认每页显示10条 lengthMenu: [10, 25, 50, 100], // 让用户可选每页显示条数 language: { // 可选:把DataTables的提示文本改成波兰语,更贴合你的场景 url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/pl.json' } }); }); </script>
为什么这样改能解决问题?
- 原来的方式一次性渲染3000+个DOM元素,浏览器需要大量时间解析和渲染,导致页面卡顿;现在每次只渲染当前页的10/25条,DOM数量骤减,加载速度会从15秒降到几百毫秒。
serverSide: true让所有分页、搜索、排序逻辑都在后端处理,前端只负责展示数据,减轻浏览器压力。deferRender: true会延迟渲染不在当前视口的行,进一步减少初始加载时的DOM操作量。
额外优化建议
- 如果你的搜索需求更复杂,可以扩展
filter里的Q条件; - 可以给
firstName和lastName字段添加数据库索引,提升搜索和排序的速度; - 操作列的链接如果是GET请求,其实可以去掉表单,直接用
<a>标签,这样更简洁。
内容的提问来源于stack exchange,提问作者Adrian Chrostowski
相关产品推荐
相关产品推荐

