Flask中如何将Jinja2循环内单选框选中值传递至不同操作表单
解决方案:通过JavaScript绑定单选框值,配合独立路由实现操作
你可以通过JavaScript监听单选框选中状态,存储选中的商品ID,然后在点击编辑/删除按钮时,直接用该ID调用对应的后端路由,完全不需要用一个大表单包裹整个页面,同时能完美适配Bootstrap模态框的编辑流程。
步骤1:前端页面结构(Jinja2渲染)
先渲染表格和操作按钮,同时准备好Bootstrap编辑模态框:
<table class="table table-striped"> <thead> <tr> <th><input type="radio" name="select-all" id="select-all" onclick="toggleAll()"></th> <th>商品名称</th> <th>商品类型</th> <th>价格</th> </tr> </thead> <tbody> {% for grocery in groceries %} <tr> <td><input type="radio" name="grocery-select" class="grocery-radio" value="{{ grocery._id }}"></td> <td>{{ grocery.name }}</td> <td>{{ grocery.type }}</td> <td>${{ "%.2f"|format(grocery.price) }}</td> </tr> {% endfor %} </tbody> </table> <!-- 顶部操作按钮 --> <div class="mb-3"> <button id="edit-btn" class="btn btn-primary me-2">编辑选中项</button> <button id="delete-btn" class="btn btn-danger">删除选中项</button> </div> <!-- Bootstrap 编辑模态框 --> <div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="editModalLabel">编辑杂货商品</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <form id="edit-form"> <div class="modal-body"> <input type="hidden" id="grocery-id" name="grocery_id"> <div class="mb-3"> <label for="grocery-name" class="form-label">商品名称</label> <input type="text" class="form-control" id="grocery-name" name="name" required> </div> <div class="mb-3"> <label for="grocery-type" class="form-label">商品类型</label> <input type="text" class="form-control" id="grocery-type" name="type" required> </div> <div class="mb-3"> <label for="grocery-price" class="form-label">价格</label> <input type="number" class="form-control" id="grocery-price" name="price" step="0.01" required> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary">保存修改</button> </div> </form> </div> </div> </div>
步骤2:JavaScript逻辑处理
用原生JS监听单选框,存储选中ID,并绑定按钮的点击事件:
// 存储当前选中的商品ID let selectedId = null; // 监听单选框选中事件 document.querySelectorAll('.grocery-radio').forEach(radio => { radio.addEventListener('change', () => { selectedId = radio.value; // 取消全选框的选中状态 document.getElementById('select-all').checked = false; }); }); // 全选/取消全选逻辑(可选) function toggleAll() { const allRadios = document.querySelectorAll('.grocery-radio'); const isChecked = document.getElementById('select-all').checked; if (isChecked) { // 全选时只选中第一个(因为单选框只能选一个) allRadios[0].checked = true; selectedId = allRadios[0].value; } else { allRadios.forEach(radio => radio.checked = false); selectedId = null; } } // 删除按钮逻辑 document.getElementById('delete-btn').addEventListener('click', () => { if (!selectedId) { alert('请先选择一个商品'); return; } if (confirm('确定要删除该商品吗?此操作不可撤销')) { // 发起DELETE请求到后端路由 fetch(`/delete/${selectedId}`, { method: 'DELETE' }).then(res => { if (res.ok) { // 删除成功后刷新页面更新表格 window.location.reload(); } else { alert('删除失败,请稍后重试'); } }).catch(err => console.error(err)); } }); // 编辑按钮逻辑 document.getElementById('edit-btn').addEventListener('click', () => { if (!selectedId) { alert('请先选择一个商品'); return; } // 先请求后端获取选中商品的当前数据 fetch(`/grocery/${selectedId}`) .then(res => res.json()) .then(data => { // 填充模态框表单 document.getElementById('grocery-id').value = data._id; document.getElementById('grocery-name').value = data.name; document.getElementById('grocery-type').value = data.type; document.getElementById('grocery-price').value = data.price; // 打开模态框 const modal = new bootstrap.Modal(document.getElementById('editModal')); modal.show(); }).catch(err => console.error(err)); }); // 编辑表单提交逻辑 document.getElementById('edit-form').addEventListener('submit', (e) => { e.preventDefault(); const groceryId = document.getElementById('grocery-id').value; const formData = new FormData(e.target); // 发起POST请求到编辑路由 fetch(`/edit/${groceryId}`, { method: 'POST', body: formData }).then(res => { if (res.ok) { // 关闭模态框并刷新页面 bootstrap.Modal.getInstance(document.getElementById('editModal')).hide(); window.location.reload(); } else { alert('修改失败,请稍后重试'); } }).catch(err => console.error(err)); });
步骤3:后端Flask路由补充
除了你已有的delete和edit路由,还需要加一个获取单条商品数据的接口,用于填充编辑模态框:
from flask import Flask, render_template, request, jsonify, redirect from pymongo import MongoClient from bson.objectid import ObjectId app = Flask(__name__) # 连接MongoDB client = MongoClient('mongodb://localhost:27017/') db = client['grocery_db'] col = db['groceries'] # 主页渲染表格 @app.route('/') def index(): groceries = list(col.find()) # 将ObjectId转为字符串,方便前端使用 for item in groceries: item['_id'] = str(item['_id']) return render_template('index.html', groceries=groceries) # 获取单条商品数据 @app.route('/grocery/<grocery_id>') def get_grocery(grocery_id): grocery = col.find_one({'_id': ObjectId(grocery_id)}) if not grocery: return jsonify({'error': '商品不存在'}), 404 grocery['_id'] = str(grocery['_id']) return jsonify(grocery) # 删除商品路由(你已有的) @app.route('/delete/<grocery_id>', methods=['DELETE']) def delete_grocery(grocery_id): result = col.delete_one({'_id': ObjectId(grocery_id)}) if result.deleted_count == 1: return '', 200 return '', 404 # 编辑商品路由(你已有的,可根据需要调整) @app.route('/edit/<grocery_id>', methods=['POST']) def edit_grocery(grocery_id): name = request.form.get('name') type_ = request.form.get('type') price = float(request.form.get('price')) update_data = { 'name': name, 'type': type_, 'price': price } result = col.update_one({'_id': ObjectId(grocery_id)}, {'$set': update_data}) if result.modified_count == 1: return '', 200 return '', 404 if __name__ == '__main__': app.run(debug=True)
核心优势
- 完全遵循你设置独立
delete和edit路由的初衷,没有用全局表单 - 单选框选中逻辑清晰,通过JS存储ID避免了Jinja2循环内外的变量传递问题
- Bootstrap模态框的编辑流程流畅,先拉取数据再填充表单,用户体验好
- 代码模块化,后续扩展其他功能(比如批量操作)也很方便
内容的提问来源于stack exchange,提问作者CowEatsGrass
相关产品推荐
相关产品推荐

