如何使用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
相关产品推荐
相关产品推荐

