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

Django中DataTable无法重新初始化及JSON数据注入问题求助

问题分析

你的代码存在三个核心问题:

  1. 错误使用Django循环包裹脚本:company是JSON字符串而非可迭代对象,{% for row in company %}会把JSON拆成单个字符循环,生成N个重复的<script>标签,每个标签都初始化一次DataTable,直接触发"Cannot reinitialise DataTable"报错。
  2. 数据格式不匹配:Django的serializers.serialize()返回的是包含model、pk、fields的嵌套JSON,而DataTables需要的是直接包含字段的扁平对象数组。
  3. Columns配置与实际数据/表格列不对应:表格列是Name、Code、Address等,但JS中columns用的是full_name、email等不存在的字段,导致数据无法渲染。
正确解决方案

提供两种常用实现方式,根据数据量选择:


方式一:直接将数据注入模板(适合小数据量)

1. 修改Views.py,构造DataTables兼容的数据格式

不用serializers.serialize,直接提取模型字段为扁平字典列表:

from main.models import Company

def company(request):
    # 按需提取字段,确保和表格列对应
    company_list = list(Company.objects.order_by('name').values(
        'id', 'name', 'code', 'address', 'remarks', 'status'
    ))
    context = {
        'company_list': company_list,
    }
    return render(request, 'admin/company.html', context)

2. 修改模板中的JS代码

去掉错误循环,将注入的数据直接传给DataTables的data选项,同时修正columns配置匹配实际字段:

{% block footer_scripts %}
<script>
$(function () {
  var dt_basic_table = $('.datatables-basic'),
    dt_basic;

  if (dt_basic_table.length) {
    dt_basic = dt_basic_table.DataTable({
      // 用|safe确保JSON格式不被转义
      data: {{ company_list|safe }},
      columns: [
        { data: null }, // 响应式控制列
        { data: null }, // 复选框列
        { data: 'id' }, // 隐藏的ID列
        { data: 'name' }, // 对应表格Name列
        { data: 'code' }, // 对应表格Code列
        { data: 'address' }, // 对应表格Address列
        { data: 'remarks' }, // 对应表格Remarks列
        { data: 'status' }, // 对应表格Status列
        { data: null } // 操作列
      ],
      columnDefs: [
        {
          className: 'control',
          orderable: false,
          searchable: false,
          responsivePriority: 2,
          targets: 0,
          render: function () {
            return '';
          }
        },
        {
          targets: 1,
          orderable: false,
          searchable: false,
          responsivePriority: 3,
          checkboxes: true,
          render: function () {
            return '<input type="checkbox" class="dt-checkboxes form-check-input">';
          },
          checkboxes: {
            selectAllRender: '<input type="checkbox" class="form-check-input">'
          }
        },
        {
          targets: 2,
          searchable: false,
          visible: false
        },
        {
          // 自定义Name列渲染逻辑
          targets: 3,
          responsivePriority: 4,
          render: function (data, type, full) {
            return `<div class="d-flex flex-column">
                      <span class="emp_name text-truncate">${full.name}</span>
                      <small class="emp_post text-truncate text-muted">${full.code}</small>
                    </div>`;
          }
        },
        {
          responsivePriority: 1,
          targets: 4
        },
        {
          // 自定义Status列渲染,根据实际status值调整映射
          targets: -2,
          render: function (data, type, full) {
            var statusMap = {
              1: { title: '活跃', class: 'bg-label-primary' },
              2: { title: '禁用', class: 'bg-label-danger' },
              // 扩展其他状态映射
            };
            if (!statusMap[data]) return data;
            return `<span class="badge ${statusMap[data].class}">${statusMap[data].title}</span>`;
          }
        },
        {
          // 操作列渲染
          targets: -1,
          render: function (data, type, full) {
            return `<div class="dropdown">
                      <button class="btn btn-sm btn-icon dropdown-toggle" type="button" data-bs-toggle="dropdown">
                        <i class="bx bx-dots-vertical-rounded"></i>
                      </button>
                      <div class="dropdown-menu dropdown-menu-end">
                        <a class="dropdown-item" href="#">编辑</a>
                        <a class="dropdown-item" href="#">删除</a>
                      </div>
                    </div>`;
          }
        }
      ]
    });
    $('div.head-label').html('<h5 class="card-title mb-0">公司列表</h5>');
  }
});
</script>
{% endblock footer_scripts %}

方式二:通过AJAX请求API加载数据(适合大数据量)

1. 添加API视图和路由

Views.py

新增返回JSON数据的视图:

from django.http import JsonResponse
from main.models import Company

def company_data(request):
    company_list = list(Company.objects.order_by('name').values(
        'id', 'name', 'code', 'address', 'remarks', 'status'
    ))
    # DataTables要求返回包含data键的JSON对象
    return JsonResponse({'data': company_list})

urls.py

添加对应路由:

from django.urls import path
from . import views

urlpatterns = [
    path('company/', views.company, name='company'),
    path('company/data/', views.company_data, name='company-data'),
]

2. 修改模板中的JS代码

将ajax选项指向API路由,其余配置和方式一一致:

{% block footer_scripts %}
<script>
$(function () {
  var dt_basic_table = $('.datatables-basic'),
    dt_basic;

  if (dt_basic_table.length) {
    dt_basic = dt_basic_table.DataTable({
      // 用Django url标签生成API地址
      ajax: '{% url "company-data" %}',
      columns: [
        { data: null },
        { data: null },
        { data: 'id' },
        { data: 'name' },
        { data: 'code' },
        { data: 'address' },
        { data: 'remarks' },
        { data: 'status' },
        { data: null }
      ],
      // 复制方式一中的columnDefs配置
      columnDefs: [
        // ... 省略重复代码
      ]
    });
    $('div.head-label').html('<h5 class="card-title mb-0">公司列表</h5>');
  }
});
</script>
{% endblock footer_scripts %}
关键注意事项
  • 确保columns的data值和模型提取的字段名完全一致。
  • 若status字段取值和示例不同,务必调整statusMap的映射关系。
  • 单个表格只需初始化一次,禁止用循环包裹初始化脚本。

内容的提问来源于stack exchange,提问作者marivic valdehueza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:54:59