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

如何使用Django为HTML表格添加行/列并同步至数据库?

Django 实现动态增行/列并同步数据库的表格

下面是基于django-tables2的完整实现方案,包含模型、视图、模板和前端交互代码:

一、安装依赖

pip install django django-tables2

二、配置项目

在settings.py的INSTALLED_APPS中添加依赖:

INSTALLED_APPS = [
    # 原有APP
    'django_tables2',
    'your_app',  # 替换为你的实际APP名称
]

# 可选:指定django-tables2的模板样式
DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html'

三、定义数据库模型

采用JSONField存储动态列数据,同时可选列配置模型管理列的状态:

from django.db import models

class TableRow(models.Model):
    row_name = models.CharField(max_length=100, verbose_name="行名称")
    # 用JSON存储动态列的键值对(键为列名,值为单元格内容)
    dynamic_columns = models.JSONField(default=dict, verbose_name="动态列数据")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "表格行"
        verbose_name_plural = "表格行"

# 可选:用于管理列的名称、排序和启用状态
class TableColumn(models.Model):
    column_name = models.CharField(max_length=100, verbose_name="列名称")
    order = models.IntegerField(default=0, verbose_name="排序")
    is_active = models.BooleanField(default=True, verbose_name="是否启用")

    class Meta:
        verbose_name = "表格列"
        verbose_name_plural = "表格列"
        ordering = ['order']

四、定义表格渲染类

通过django-tables2动态生成表格列:

import django_tables2 as tables
from .models import TableRow, TableColumn

class DynamicTable(tables.Table):
    row_name = tables.Column(verbose_name="行名称")

    class Meta:
        model = TableRow
        template_name = "django_tables2/bootstrap4.html"
        fields = ['row_name']

五、编写视图逻辑

处理表格渲染、AJAX提交的增行/列请求:

from django.shortcuts import render
from django.http import JsonResponse
from .models import TableRow, TableColumn
from .tables import DynamicTable
import json

def dynamic_table_view(request):
    # 获取所有启用的列
    active_columns = TableColumn.objects.filter(is_active=True)
    # 动态给表格类添加列
    dynamic_table_class = type(
        'DynamicTableWithColumns',
        (DynamicTable,),
        {
            col.column_name: tables.Column(
                verbose_name=col.column_name,
                accessor=tables.A(f'dynamic_columns__{col.column_name}')
            )
            for col in active_columns
        }
    )
    # 获取行数据并初始化表格
    table = dynamic_table_class(TableRow.objects.all())

    if request.method == 'POST':
        data = json.loads(request.body)
        action = data.get('action')

        # 新增列
        if action == 'add_column':
            col_name = data.get('column_name')
            if not TableColumn.objects.filter(column_name=col_name).exists():
                TableColumn.objects.create(column_name=col_name)
                # 给已有行添加新列的默认值
                for row in TableRow.objects.all():
                    if col_name not in row.dynamic_columns:
                        row.dynamic_columns[col_name] = ""
                        row.save()
                return JsonResponse({'status': 'success', 'msg': '列添加成功'})
            return JsonResponse({'status': 'error', 'msg': '该列已存在'})
        
        # 新增行
        elif action == 'add_row':
            row_name = data.get('row_name')
            if not row_name:
                return JsonResponse({'status': 'error', 'msg': '行名称不能为空'})
            # 构建新行的动态列默认数据
            dynamic_data = {col.column_name: "" for col in active_columns}
            TableRow.objects.create(row_name=row_name, dynamic_columns=dynamic_data)
            return JsonResponse({'status': 'success', 'msg': '行添加成功'})
        
        # 保存单元格编辑内容
        elif action == 'save_cell':
            row_id = data.get('row_id')
            col_name = data.get('column_name')
            value = data.get('value')
            try:
                row = TableRow.objects.get(id=row_id)
                row.dynamic_columns[col_name] = value
                row.save()
                return JsonResponse({'status': 'success'})
            except TableRow.DoesNotExist:
                return JsonResponse({'status': 'error', 'msg': '目标行不存在'})

    return render(request, 'dynamic_table.html', {'table': table, 'columns': active_columns})

六、编写前端模板

实现动态操作按钮和AJAX交互:

{% load django_tables2 %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>动态表格</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css">
    {% render_table table %}
    {% csrf_token %}
</head>
<body>
    <div class="container mt-4">
        <h2>可动态增行/列的表格</h2>
        <div class="mb-3">
            <button id="addColBtn" class="btn btn-primary mr-2">新增列</button>
            <button id="addRowBtn" class="btn btn-success">新增行</button>
        </div>
        <div id="tableContainer">
            {% render_table table %}
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
    <script>
        // 获取CSRF令牌,用于AJAX请求
        function getCookie(name) {
            let cookieValue = null;
            if (document.cookie && document.cookie !== '') {
                const cookies = document.cookie.split(';');
                for (let i = 0; i < cookies.length; i++) {
                    const cookie = cookies[i].trim();
                    if (cookie.substring(0, name.length + 1) === (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        const csrftoken = getCookie('csrftoken');

        // 新增列逻辑
        $('#addColBtn').click(function() {
            const colName = prompt('请输入列名称:');
            if (!colName) return;
            $.ajax({
                url: window.location.href,
                method: 'POST',
                contentType: 'application/json',
                headers: {'X-CSRFToken': csrftoken},
                data: JSON.stringify({action: 'add_column', column_name: colName}),
                success: res => {
                    alert(res.msg);
                    if (res.status === 'success') window.location.reload();
                }
            });
        });

        // 新增行逻辑
        $('#addRowBtn').click(function() {
            const rowName = prompt('请输入行名称:');
            if (!rowName) return;
            $.ajax({
                url: window.location.href,
                method: 'POST',
                contentType: 'application/json',
                headers: {'X-CSRFToken': csrftoken},
                data: JSON.stringify({action: 'add_row', row_name: rowName}),
                success: res => {
                    alert(res.msg);
                    if (res.status === 'success') window.location.reload();
                }
            });
        });

        // 单元格实时编辑保存
        $('#tableContainer td').click(function() {
            const $td = $(this);
            const originalVal = $td.text();
            const $input = $('<input type="text" class="form-control" value="' + originalVal + '">');
            $td.html($input);
            $input.focus();

            $input.blur(function() {
                const newVal = $(this).val();
                if (newVal === originalVal) {
                    $td.text(originalVal);
                    return;
                }
                const rowId = $td.closest('tr').attr('data-id'); // 需要在表格类中添加row的ID属性
                const colName = $td.closest('table').find('th').eq($td.index()).text();
                
                $.ajax({
                    url: window.location.href,
                    method: 'POST',
                    contentType: 'application/json',
                    headers: {'X-CSRFToken': csrftoken},
                    data: JSON.stringify({
                        action: 'save_cell',
                        row_id: rowId,
                        column_name: colName,
                        value: newVal
                    }),
                    success: res => {
                        $td.text(res.status === 'success' ? newVal : originalVal);
                    }
                });
            });
        });
    </script>
</body>
</html>

七、配置URL路由

from django.urls import path
from .views import dynamic_table_view

urlpatterns = [
    path('dynamic-table/', dynamic_table_view, name='dynamic_table'),
]

八、注意事项

  • 示例用JSONField存储动态列,适合中小规模场景;若需复杂查询,可改用关联表设计
  • 前端采用页面刷新展示新行列,也可通过AJAX局部更新表格提升体验
  • 可添加表单验证逻辑,比如限制列名/行名的格式和长度
  • 生产环境建议优化静态资源加载方式,避免依赖CDN

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:45:39