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

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)

核心优势

  1. 完全遵循你设置独立delete和edit路由的初衷,没有用全局表单
  2. 单选框选中逻辑清晰,通过JS存储ID避免了Jinja2循环内外的变量传递问题
  3. Bootstrap模态框的编辑流程流畅,先拉取数据再填充表单,用户体验好
  4. 代码模块化,后续扩展其他功能(比如批量操作)也很方便

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:17:00