You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Flask与Jinja实现SQL数据库可编辑表格的方案咨询

嘿,我来帮你搞定这个需求!其实这确实是Web开发里非常常见的场景,结合你已经掌握的Flask和Jinja知识,咱们一步步拆解实现:

一、前端实现可编辑表格与行操作

首先咱们要把静态表格改成可编辑的,再加上行的增删按钮,最后用JS收集修改后的数据提交给后端。

1. 用Jinja渲染可编辑基础表格

利用HTML的contenteditable属性让单元格变成可编辑状态,同时给每行加上对应数据库主键的data-id属性,方便后端识别是哪条数据:

<!DOCTYPE html>
<html>
<head>
    <title>可编辑表格</title>
    <style>
        table { border-collapse: collapse; width: 80%; margin: 20px auto; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        [contenteditable] { background-color: #fff9c4; }
        button { padding: 5px 10px; margin: 0 5px; cursor: pointer; }
    </style>
</head>
<body>
    <h1 style="text-align: center;">可编辑用户表格</h1>
    <table id="editable-table">
        <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>邮箱</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for user in users %}
            <tr data-id="{{ user.id }}">
                <td>{{ user.id }}</td>
                <td contenteditable="true" class="cell-name">{{ user.name }}</td>
                <td contenteditable="true" class="cell-email">{{ user.email }}</td>
                <td><button class="delete-row">删除</button></td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    <div style="text-align: center;">
        <button id="add-row">添加新行</button>
        <button id="save-changes">保存所有修改</button>
    </div>

    <script>
        // 绑定删除行事件
        document.querySelectorAll('.delete-row').forEach(btn => {
            btn.addEventListener('click', function() {
                this.closest('tr').remove();
            });
        });

        // 添加新行功能
        document.getElementById('add-row').addEventListener('click', function() {
            const tbody = document.querySelector('#editable-table tbody');
            const newRow = document.createElement('tr');
            newRow.innerHTML = `
                <td>新增</td>
                <td contenteditable="true" class="cell-name"></td>
                <td contenteditable="true" class="cell-email"></td>
                <td><button class="delete-row">删除</button></td>
            `;
            tbody.appendChild(newRow);
            // 给新行的删除按钮绑定事件
            newRow.querySelector('.delete-row').addEventListener('click', function() {
                newRow.remove();
            });
        });

        // 收集数据并提交到Flask后端
        document.getElementById('save-changes').addEventListener('click', function() {
            const rows = document.querySelectorAll('#editable-table tbody tr');
            const tableData = [];

            rows.forEach(row => {
                const rowId = row.getAttribute('data-id');
                const name = row.querySelector('.cell-name').textContent.trim();
                const email = row.querySelector('.cell-email').textContent.trim();

                if (name && email) { // 确保必填字段不为空
                    tableData.push({
                        id: rowId ? parseInt(rowId) : null, // 新增行id为null
                        name: name,
                        email: email
                    });
                }
            });

            // 发送POST请求
            fetch('/save-table', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': '{{ csrf_token() }}' // 启用CSRF保护时必须加
                },
                body: JSON.stringify(tableData)
            })
            .then(res => res.json())
            .then(result => {
                if (result.success) {
                    alert('修改保存成功!');
                    window.location.reload(); // 刷新页面更新表格
                } else {
                    alert('保存失败:' + result.message);
                }
            })
            .catch(err => console.error('提交出错:', err));
        });
    </script>
</body>
</html>
二、Flask后端处理提交的数据

后端需要接收前端传来的JSON数据,分别处理新增、更新、删除三种操作:

from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://用户名:密码@localhost/数据库名' # 替换成你的数据库连接
app.config['SECRET_KEY'] = 'your-secret-key-here' # CSRF保护需要的密钥
db = SQLAlchemy(app)
csrf = CSRFProtect(app)

# 定义数据库模型(对应你的表结构)
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)

# 展示表格页面
@app.route('/')
def index():
    users = User.query.all()
    return render_template('index.html', users=users)

# 处理表格数据提交
@app.route('/save-table', methods=['POST'])
def save_table():
    try:
        data = request.get_json()
        if not data:
            return jsonify({'success': False, 'message': '未收到有效数据'})
        
        # 1. 处理删除:删除数据库中存在但提交数据里没有的行
        submitted_ids = [item['id'] for item in data if item['id'] is not None]
        User.query.filter(User.id.notin_(submitted_ids)).delete(synchronize_session=False)
        
        # 2. 处理新增和更新
        for item in data:
            if item['id'] is None:
                # 新增记录
                new_user = User(name=item['name'], email=item['email'])
                db.session.add(new_user)
            else:
                # 更新现有记录
                user = User.query.get(item['id'])
                if user:
                    user.name = item['name']
                    user.email = item['email']
        
        db.session.commit()
        return jsonify({'success': True, 'message': '数据保存成功'})
    
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)})

if __name__ == '__main__':
    with app.app_context():
        db.create_all() # 第一次运行时创建表
    app.run(debug=True)
三、关键注意事项
  • CSRF保护:如果你的Flask应用启用了CSRF保护(如示例中用CSRFProtect),一定要在前端请求中带上X-CSRFToken头,否则请求会被拒绝。
  • 数据验证:前端的非空验证只是基础,后端必须再做一次数据校验(比如邮箱格式、字段长度等),避免恶意数据写入数据库。
  • 错误处理:后端要捕获数据库操作的异常,执行事务回滚,再返回友好的错误信息给前端。
  • 性能优化:如果表格数据量很大,不要一次性提交所有行,可以在前端记录哪些行被修改/新增/删除,只提交变更的数据,减少请求体积。

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

火山引擎 最新活动