You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。
  • 虚拟滚动:搭配前端表格的虚拟滚动功能,仅渲染可视区域内的行,不管总数据量多少都不会卡顿。
优化注意点
  1. 给常用搜索、排序字段加数据库索引:在PartyMaster模型的party_name、email、contact等字段上添加db_index=True,可以大幅提升搜索排序速度。
  2. 全量导出优化:如果需要导出全量5万+数据,不要用前端导出功能,建议单独做后端导出接口,避免前端处理大量数据卡顿。
  3. 接口缓存:如果数据更新频率不高,可以给party_list_ajax接口加缓存,进一步提升响应速度。

内容的提问来源于stack exchange,提问作者Pulkit Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 15:15:00