Django中使用Bootstrap Modal传递Model ID到URL的异常问题
Django + Bootstrap 5 删除模态框异常问题解决
问题现象
在Django项目中使用Bootstrap 5模态框实现删除确认对话框时,出现以下异常:
- 点击表格任意行的删除按钮,模态框始终显示数据库中第一条Service数据的名称
- 跳转的删除URL仅指向第一条数据的ID(例如点击第9行删除按钮,URL指向ID为7的条目)
- 点击删除按钮后第一行会变灰
用户提供的模板代码:
{% extends 'base.html' %} {% block content %} <div class="col-md-6 offset-md-3"> {% if messages %} {% for message in messages %} <div class="alert alert-success alert-dismissible fade show" role="alert"> {{ message }} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> {% endfor %} {% endif %} </div> <h1>Service Overview</h1> <br/> <div class="d-grid gap-2 justify-content-md-end"> <a class="btn btn-primary" href="{% url 'add_service' %}">Add service</a> <br/> </div> <table class="table table-hover table-bordered"> <thead class="table-secondary"> <tr> <th class="text-center" scope="col">#</th> <th scope="col">Name</th> <th scope="col">Description</th> <th class="text-center" scope="col">Cost</th> <th class="text-center" scope="col">Created at</th> <th class="text-center" scope="col">Updated at</th> <th class="text-center" scope="col">Status</th> <th class="text-center" scope="col">Actions</th> </tr> </thead> <tbody> {% for service in services %} <tr> <td class="text-center">{{ service.id }}</td> <td>{{ service.name }}</td> <td>{{ service.description}}</td> <td class="text-center">{{ service.cost }} AED</td> <td class="text-center">{{ service.created_date }}</td> <td class="text-center">{{ service.updated_date }}</td> {% if service.status == "ACTIVE" %} <td class="text-center"> <span class="badge text-bg-success" style="font-size:0.7em;">{{ service.status }}</span> </td> {% elif service.status == "INACTIVE"%} <td class="text-center"> <span class="badge text-bg-danger" style="font-size:0.7em;">{{ service.status }}</span> </td> {% endif %} <td class="text-center"> <!--Update--> <a href="{% url 'service_record' service.id %}" class="text-decoration-none"> <button type="button" class="btn btn-warning btn-sm" data-bs-toggle="tooltip" title="Update service"> <i class="bi bi-pencil-fill"></i> </button> </a> <!--Delete modal--> <!-- Button trigger modal --> <button type="button" class="btn btn-danger btn-sm" data-bs-toggle="modal" data-bs-target="#DeleteDialogueModal"> <i class="bi bi-trash"></i> </button> <!-- Modal --> <div class="modal fade" id="DeleteDialogueModal" tabindex="-1" aria-labelledby="modal-title" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="modal-title">Delete service: {{ service.name }}</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Are you sure to delete the service {{ service.name }} ?</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Go back</button> <a class="btn btn-danger" href="{% url 'delete_service' service.id %}">Yes, delete</a> </div> </div> </div> </div> </td> </tr> {% endfor %} </tbody> </table> {% endblock content %} {% block javascripts %} <script> // Alert when trying to delete a product const myModal = document.getElementById('myModal') const myInput = document.getElementById('myInput') myModal.addEventListener('shown.bs.modal', () => { myInput.focus() }) </script> {% endblock javascripts %}
问题根源
在{% for service in services %}循环内重复渲染了ID为DeleteDialogueModal的模态框,但HTML要求ID必须唯一。当点击删除按钮时,Bootstrap会查找页面中第一个匹配data-bs-target="#DeleteDialogueModal"的元素,也就是循环生成的第一个模态框,因此始终显示第一条数据的内容。
解决方案
方案一:为每个模态框生成唯一ID
修改循环内的模态框ID和按钮的data-bs-target,用service.id作为唯一标识:
<!-- Button trigger modal --> <button type="button" class="btn btn-danger btn-sm" data-bs-toggle="modal" data-bs-target="#DeleteDialogueModal-{{ service.id }}"> <i class="bi bi-trash"></i> </button> <!-- Modal --> <div class="modal fade" id="DeleteDialogueModal-{{ service.id }}" tabindex="-1" aria-labelledby="modal-title-{{ service.id }}" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="modal-title-{{ service.id }}">Delete service: {{ service.name }}</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Are you sure to delete the service {{ service.name }} ?</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Go back</button> <a class="btn btn-danger" href="{% url 'delete_service' service.id %}">Yes, delete</a> </div> </div> </div> </div>
方案二:使用单个模态框动态填充内容(更优,减少DOM元素)
只渲染一个模态框,通过JavaScript动态传递当前要删除的服务信息:
- 修改模板,将模态框移到循环外,按钮添加自定义属性存储服务数据:
<!-- 循环内的删除按钮 --> <button type="button" class="btn btn-danger btn-sm delete-btn" data-bs-toggle="modal" data-bs-target="#DeleteDialogueModal" data-service-id="{{ service.id }}" data-service-name="{{ service.name }}" data-delete-url="{% url 'delete_service' service.id %}"> <i class="bi bi-trash"></i> </button> <!-- 模态框移到表格结束后 --> <div class="modal fade" id="DeleteDialogueModal" tabindex="-1" aria-labelledby="modal-title" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="modal-title">Delete service: <span id="service-name"></span></h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p>Are you sure to delete the service <span id="service-name-body"></span> ?</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Go back</button> <a class="btn btn-danger" id="delete-link" href="#">Yes, delete</a> </div> </div> </div> </div>
- 更新JavaScript代码,监听模态框显示事件并动态填充内容:
<script> const deleteModal = document.getElementById('DeleteDialogueModal'); const deleteLink = document.getElementById('delete-link'); const serviceNameTitle = document.getElementById('service-name'); const serviceNameBody = document.getElementById('service-name-body'); deleteModal.addEventListener('show.bs.modal', function (event) { // 获取触发模态框的按钮 const button = event.relatedTarget; // 读取按钮上存储的服务数据 const serviceName = button.getAttribute('data-service-name'); const deleteUrl = button.getAttribute('data-delete-url'); // 更新模态框内容和删除链接 serviceNameTitle.textContent = serviceName; serviceNameBody.textContent = serviceName; deleteLink.href = deleteUrl; }); </script>
内容的提问来源于stack exchange,提问作者LeXXan
相关产品推荐
相关产品推荐

