Django:如何使用模态框删除一个对象?

huangapple go评论71阅读模式
英文:

Django: How to use a modal to delete an object?

问题

在我提供的翻译中,我只会返回代码的翻译部分,不包括问题的回答或额外的内容。

在索引页面上,我包含了一个按钮来删除一个未使用的食物对象。删除按钮启动了一个基于Bootstrap 5的模态删除表单。但是当我点击删除按钮时,错误信息中包含了索引页面的名称。在下面的代码中,可以在哪里和如何修复这个问题?

期望的删除URL:.../food/1/delete

页面未找到:Request URL: http://127.0.0.1:8000/food/foodIndex/1/delete

值得注意的是,404错误将请求视为GET而不是POST

food/urls.py:

urlpatterns = [
    path('foodIndex/', views.foodIndex, name="foodIndex"),
    path('<int:id>/edit/', views.foodEdit, name="foodEdit"),
    path('<int:id>/foodDelete/', views.foodDelete, name="foodDelete")
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

注意:path('foodIndex/<int:id>/foodDelete/', ... 不能解决这个问题。

在“.../food/foodIndex.html”中包含的模板部分:

{% if allFoods.count > 0 %}
    {% for food in allFoods %}
        <tr>
            <td data-foodid="{{ food.id }}">{{ food }}</td>
            <td><a class="btn p-0" href='{% url "food:foodEdit" food.id %}'>Edit</a></td>
            {% if food.used == False %}
            <td><button id='btn_delete' type="button" class="btn p-0" data-bs-toggle="modal" data-bs-target="#modal-delete" data-bs-foodid='{{ food.id }}' data-bs-foodname='{{ food }}'>Delete</button></td>
            {% endif %}
        </tr>
    {% endfor %}
{% else %}
    <tr>
        <td colspan="3">no records found</td>
    </tr>
{% endif %}

“.../food/foodIndex.html”中的模态框部分:

<div id="modal-delete" class="modal fade" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Delete food item</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                <form >
                    <button id='food-delete' class="btn btn-warning" type="submit">Delete</button>
                </form>
            </div>
        </div>
    </div>
</div>

删除表单部分:

{<form method="POST" action="{% url 'food:foodDelete' pk=food.id %}" onsubmit="return confirm('Are you sure you want to delete this item?');">
    <button class="btn">Delete</button>
</form>}

用于模态框的JavaScript部分:

const deleteModal = document.getElementById('modal-delete');
deleteModal.addEventListener('show.bs.modal', event => {
    const button = event.relatedTarget
    const foodName = button.getAttribute('data-bs-foodname')
    const foodId = button.getAttribute('data-bs-foodid')
    const modalBodyInput = deleteModal.querySelector('.modal-body ')
    const modalFooterButtons= deleteModal.querySelector('form')

    modalBodyInput.textContent = `Confirm deletion of ${foodName}`
    modalFooterButtons.setAttribute('action',`${foodId}/delete`)
});
英文:

On the index page for a list of food objects I've included a button to delete an object that is not used. The delete button launches a Bootstrap 5 modal delete form. But when I click the Delete button, the error thrown includes the name of index page. In the code below, where & how can this be fixed?

Expected url on delete: .../food/1/delete

Page not found: Request URL: http://127.0.0.1:8000/food/foodIndex/1/delete

It may be worth noting that the 404 error considers the request to be GET rather than POST

[I'm attempting to learn Python & Django by recreating a working PHP project. All of the HTML & javascript comes from that project.]

food/urls.py:

urlpatterns = [
    path(&#39;foodIndex/&#39;, views.foodIndex, name=&quot;foodIndex&quot;),
    path(&#39;&lt;int:id&gt;/edit/&#39;, views.foodEdit, name=&quot;foodEdit&quot;),
    path(&#39;&lt;int:id&gt;/foodDelete/&#39;, views.foodDelete, name = &quot;foodDelete&quot;)
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Note: a path(&#39;foodIndex/&lt;int:id&gt;/foodDelete/&#39;,... does not solve the problem

Template included in ".../food/foodIndex.html":

{% if allFoods.count &gt; 0 %}
    {% for food in allFoods %}
        &lt;tr&gt;
            &lt;td data-foodid=&quot;{{ food.id }}&quot;&gt;{{ food }}&lt;/td&gt;
            &lt;td&gt;&lt;a class=&quot;btn p-0&quot; href=&#39;{% url &quot;food:foodEdit&quot; food.id %}&#39;&gt;Edit&lt;/a&gt;&lt;/td&gt;
            {% if food.used == False %}
            &lt;td&gt;&lt;button id=&#39;btn_delete&#39; type=&quot;button&quot; class=&quot;btn p-0&quot; data-bs-toggle=&quot;modal&quot; data-bs-target=&quot;#modal-delete&quot; data-bs-foodid=&#39;{{ food.id }}&#39; data-bs-foodname=&#39;{{ food }}&#39;&gt;Delete&lt;/button&gt;&lt;/td&gt;
            {% endif %}
        &lt;/tr&gt;
    {% endfor %}
{% else %}
    &lt;tr&gt;
        &lt;td colspan=&quot;3&quot;&gt;no records found&lt;/td&gt;
    &lt;/tr&gt;
{% endif %}

Modal in ".../food/foodIndex.html":

&lt;div id=&quot;modal-delete&quot; class=&quot;modal fade&quot; tabindex=&quot;-1&quot;&gt;
    &lt;div class=&quot;modal-dialog&quot;&gt;
        &lt;div class=&quot;modal-content&quot;&gt;
            &lt;div class=&quot;modal-header&quot;&gt;
                &lt;h5 class=&quot;modal-title&quot;&gt;Delete food item&lt;/h5&gt;
                &lt;button type=&quot;button&quot; class=&quot;btn-close&quot; data-bs-dismiss=&quot;modal&quot; aria-label=&quot;Close&quot;&gt;&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-body&quot;&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-footer&quot;&gt;
                &lt;button type=&quot;button&quot; class=&quot;btn btn-secondary&quot; data-bs-dismiss=&quot;modal&quot;&gt;Close&lt;/button&gt;
                &lt;form &gt;
                    &lt;button id=&#39;food-delete&#39; class=&quot;btn btn-warning&quot; type=&quot;submit&quot;&gt;Delete&lt;/button&gt;
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

delete form:

{&lt;form method=&quot;POST&quot; action=&quot;{% url &#39;food:foodDelete&#39; pk=food.id %}&quot; onsubmit=&quot;return confirm(&#39;Are you sure you want to delete this item?&#39;);&quot;&gt;
    &lt;button class=&quot;btn&quot;&gt;Delete&lt;/button&gt;
&lt;/form&gt;}

javascript for modal:

const deleteModal = document.getElementById(&#39;modal-delete&#39;);
deleteModal.addEventListener(&#39;show.bs.modal&#39;, event =&gt; {
    const button = event.relatedTarget
    const foodName = button.getAttribute(&#39;data-bs-foodname&#39;)
    const foodId = button.getAttribute(&#39;data-bs-foodid&#39;)
    const modalBodyInput = deleteModal.querySelector(&#39;.modal-body &#39;)
    const modalFooterButtons= deleteModal.querySelector(&#39;form&#39;)

    modalBodyInput.textContent = `Confirm deletion of ${foodName}`
    modalFooterButtons.setAttribute(&#39;action&#39;,`${foodId}/delete`)
}
);

答案1

得分: 0

问题出在您构建URL的方式上。

deleteModal.addEventListener('show.bs.modal', event => {
    ...
    modalFooterButtons.setAttribute('action',`${foodId}/delete`)
});

这将始终只产生 some-id/delete 作为您的操作,您没有构建完整的路径。一个简单的解决方案是使用 DTL 来构建您的 URL,使用 reverse resolution,就像在您的 delete form 代码块中一样。

但是,可以将其作为表格删除按钮的属性使用(可以直接替换 data-bs-foodid)。

<button 
    id='btn-delete' 
    class="btn-warning" 
    data-bs-toggle="modal" 
    data-bs-target="#modal-delete" 
    data-bs-foodname='{{ food }}' 
    data-bs-url="{% url 'food:foodDelete' food.id %}"
>
    Delete
</button>

然后,我们使用相同的JavaScript方法检索它并在表单上设置这些值。

deleteModal.addEventListener('show.bs.modal', event => {
    ...
    const deleteForm = deleteModal.querySelector('form');
    const url = button.getAttribute('data-bs-url');
    deleteForm.setAttribute('action', url);
    deleteForm.setAttribute('method', 'post');
});

全面示例:

foodIndex.html(带有食物的表格)

<table class="table">
    <thead>
        <tr>
            <th scope="col">Name</th>
            <th scope="col" colspan="2">Actions</th>
        </tr>
    </thead>
    <tbody>
    {% if allFoods.count > 0 %}
        {% for food in allFoods %}
        <tr>
            <th scope="row">{{food.name}}</th>
            <td><button>Edit</button></td>
            <td>
                <button 
                    id='btn-delete' 
                    class="btn-warning" 
                    data-bs-toggle="modal" 
                    data-bs-target="#modal-delete" 
                    data-bs-foodname='{{ food }}' 
                    data-bs-url="{% url 'food:foodDelete' food.id %}"
                >
                    Delete
                </button>
            </td>
        </tr>
        {% endfor %}
    {% else %}
        <tr>
            <td colspan="3">no records found</td>
        </tr>
    {% endif %}
    </tbody>
</table>

foodIndex.html(Modal - 注意 {% csrf_token %}

<div id="modal-delete" class="modal fade" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Delete food item</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                <form>
                    {% csrf_token %}
                    <button id='food-delete' class="btn btn-danger" type="submit">Delete</button>
                </form>
            </div>
        </div>
    </div>
</div>

foodIndex.html(脚本)

<script>
    const deleteModal = document.getElementById('modal-delete');

    deleteModal.addEventListener('show.bs.modal', event => {
        const button = event.relatedTarget;
        const foodName = button.getAttribute('data-bs-foodname');
        const url = button.getAttribute('data-bs-url');
        const modalBodyInput = deleteModal.querySelector('.modal-body ');

        modalBodyInput.textContent = `Confirm deletion of ${foodName}`;

        const deleteForm = deleteModal.querySelector('form');
        deleteForm.setAttribute('action', url);
        deleteForm.setAttribute('method', 'post');
    });
</script>

<details>
<summary>英文:</summary>

The problem is in the form on how you are building your URL.
```JavaScript
deleteModal.addEventListener(&#39;show.bs.modal&#39;, event =&gt; {
    ...
    modalFooterButtons.setAttribute(&#39;action&#39;,`${foodId}/delete`)
}
);

That will always yield just some-id/delete as your action, you are not building the full path. One simple solution would be to use DTL to build your URL using reverse resolution, just like in your delete form code block.

But, instead, use that as an attribute of the table delete button (you can just replace data-bs-foodid)

&lt;button 
    id=&#39;btn-delete&#39; 
    class=&quot;btn-warning&quot; 
    data-bs-toggle=&quot;modal&quot; 
    data-bs-target=&quot;#modal-delete&quot; 
    data-bs-foodname=&#39;{{ food }}&#39; 
    data-bs-url=&quot;{% url &#39;food:foodDelete&#39; food.id %}&quot;
&gt;
    Delete
&lt;/button&gt;

Then, we retrieve it and set those values on the form using the same method with JavaScript:

deleteModal.addEventListener(&#39;show.bs.modal&#39;, event =&gt; {
    ...
    const deleteForm= deleteModal.querySelector(&#39;form&#39;);
    const url = button.getAttribute(&#39;data-bs-url&#39;);
    deleteForm.setAttribute(&#39;action&#39;, url);
    deleteForm.setAttribute(&#39;method&#39;, &#39;post&#39;);
});

<h2>Full example</h2>

foodIndex.html (Table with Foods)

&lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
        &lt;th scope=&quot;col&quot;&gt;Name&lt;/th&gt;
        &lt;th scope=&quot;col&quot; colspan=&quot;2&quot;&gt;Actions&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    {% if allFoods.count &gt; 0 %}
        {% for food in allFoods %}
        &lt;tr&gt;
            &lt;th scope=&quot;row&quot;&gt;{{food.name}}&lt;/th&gt;
            &lt;td&gt;&lt;button&gt;Edit&lt;/button&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;button 
                    id=&#39;btn-delete&#39; 
                    class=&quot;btn-warning&quot; 
                    data-bs-toggle=&quot;modal&quot; 
                    data-bs-target=&quot;#modal-delete&quot; 
                    data-bs-foodname=&#39;{{ food }}&#39; 
                    data-bs-url=&quot;{% url &#39;food:foodDelete&#39; food.id %}&quot;
                &gt;
                    Delete
                &lt;/button&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        {% endfor %}
    {% else %}
        &lt;tr&gt;
            &lt;td colspan=&quot;3&quot;&gt;no records found&lt;/td&gt;
        &lt;/tr&gt;
    {% endif %}
    &lt;/tbody&gt;
&lt;/table&gt;

foodIndex.html (Modal - Note {% csrf_token %})

&lt;div id=&quot;modal-delete&quot; class=&quot;modal fade&quot; tabindex=&quot;-1&quot;&gt;
    &lt;div class=&quot;modal-dialog&quot;&gt;
        &lt;div class=&quot;modal-content&quot;&gt;
            &lt;div class=&quot;modal-header&quot;&gt;
                &lt;h5 class=&quot;modal-title&quot;&gt;Delete food item&lt;/h5&gt;
                &lt;button type=&quot;button&quot; class=&quot;btn-close&quot; data-bs-dismiss=&quot;modal&quot; aria-label=&quot;Close&quot;&gt;&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-body&quot;&gt;
            &lt;/div&gt;
            &lt;div class=&quot;modal-footer&quot;&gt;
                &lt;button type=&quot;button&quot; class=&quot;btn btn-secondary&quot; data-bs-dismiss=&quot;modal&quot;&gt;Close&lt;/button&gt;
                &lt;form&gt;
                    {% csrf_token %}
                    &lt;button id=&#39;food-delete&#39; class=&quot;btn btn-danger&quot; type=&quot;submit&quot;&gt;Delete&lt;/button&gt;
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

foodIndex.html (script)

&lt;script&gt;
    const deleteModal = document.getElementById(&#39;modal-delete&#39;);

    deleteModal.addEventListener(&#39;show.bs.modal&#39;, event =&gt; {
        const button = event.relatedTarget;
        const foodName = button.getAttribute(&#39;data-bs-foodname&#39;);
        const url = button.getAttribute(&#39;data-bs-url&#39;);
        const modalBodyInput = deleteModal.querySelector(&#39;.modal-body &#39;);

        modalBodyInput.textContent = `Confirm deletion of ${foodName}`;

        const deleteForm= deleteModal.querySelector(&#39;form&#39;);
        deleteForm.setAttribute(&#39;action&#39;, url);
        deleteForm.setAttribute(&#39;method&#39;, &#39;post&#39;);
    });
&lt;/script&gt;

huangapple
  • 本文由 发表于 2023年6月15日 07:08:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76478109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定