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

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动态传递当前要删除的服务信息:

  1. 修改模板,将模态框移到循环外,按钮添加自定义属性存储服务数据:
<!-- 循环内的删除按钮 -->
<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>
  1. 更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:08:15