(Django) Функция Delete не удаляет данные из базы данных

В настоящее время у меня есть таблица, в которой отображается список лекарств. В этой таблице в каждой строке данных есть кнопка удаления. Когда я нажимаю на нее, строка не удаляется.

Я попробовал тот же синтаксис удаления (в функции под названием 'destroy') в Django shell и это сработало. Я просто не понимаю, почему, когда я нажал на кнопку Remove внутри шаблона, ничего не произошло, даже после обновления.

drugs/views.py

from django.shortcuts import render, redirect
from django.views.generic import ListView
from .models import (
    Drug,
)
from .forms import (
    DrugForm,
)
def add_drug(request):
    forms = DrugForm()
    if request.method == 'POST':
        forms = DrugForm(request.POST)
        if forms.is_valid():
            drug_id = forms.cleaned_data['drug_id']
            name = forms.cleaned_data['name']
            drug_type = forms.cleaned_data['drug_type']
            Drug.objects.create(drug_id=drug_id, name=name, 
                                drug_type=drug_type)
            return redirect('drug-list')
    context = {
        'form': forms
    }
    return render(request, 'drugs/add_drug.html', context)    
def destroy(request, drug_id):  
    d = Drug.objects.get(drug_id=drug_id)  
    d.delete()  
    d.save()
    return redirect("/")     
class DrugListView(ListView):
    model = Drug
    template_name = 'drugs/drug_list.html'
    context_object_name = 'drug'

ddms/urls.py

from django.contrib import admin
from django.urls import path, include
# local
from .views import base, dashboard
from drugs.views import destroy


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', dashboard, name='dashboard'),
    path('drugs/', include('drugs.urls')),
    path('delete/<int:drug_id>', destroy), 
]

templates/drugs/drug_list.html

<div class="card-body--">
    <div class="table-stats order-table ov-h">
        <table id="bootstrapdatatable" class="table">
            <thead>
                <tr>
                    {% comment %} <th class="serial">#</th> {% endcomment %}
                    <th>ID</th>
                    <th>Name</th>
                    <th>Type</th>
                    <th>ACTION</th>
                </tr>
            </thead>
            <tbody>
                {% if drug %}
                {% for drug in drug %}
                <tr>
                    {% comment %} <td class="serial">{{ forloop.counter }}</td> {% endcomment %}
                    <td>{{ drug.drug_id }}</td>
                    <td>{{ drug.name }}</td>
                    <td>{{ drug.drug_type }}</td>
                    <td>
                        <div class="btn-group">
                            <button class="btn btn-link text-dark m-1 p-0" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                <span class="">
                                    <span id="action-button" class="fas fa-ellipsis-h icon-dark"></span>
                                </span>
                            </button>
                            <div class="dropdown-menu">
                                <a class="dropdown-item" href="#"><span class="fas fa-edit mr-2"></span>Edit</a>
                                <a class="dropdown-item text-danger" href="/delete/{{ drug.drug_id }}" data-title="Delete" data-toggle="modal" data-target="#delete"><span class="fas fa-trash-alt mr-2"></span>Remove</a>
                            </div>
                        </div>
                    </td>
                </tr>
                {% endfor %}
                {% else %}
                    <tr><td>No Drug Data</td></tr>
                {% endif %}
            </tbody>
        </table>
    </div>
</div>

drugs/models.py

from django.db import models
from .drug_types import drug_types_list


class Drug(models.Model):
    drug_id = models.CharField(max_length=20)
    name = models.CharField(max_length=50, unique=True)
    drug_type = models.CharField(max_length=20, choices=drug_types_list, default='pills')
    def __str__(self):
        return self.name

Мое предположение: если функция в views.py не виновата, то проблема может быть внутри моего шаблона, в кнопке Remove?

<td>
    <div class="btn-group">
        <button class="btn btn-link text-dark m-1 p-0" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <span class="">
                <span id="action-button" class="fas fa-ellipsis-h icon-dark"></span>
            </span>
        </button>
        <div class="dropdown-menu">
            <a class="dropdown-item" href="#"><span class="fas fa-edit mr-2"></span>Edit</a>
            <a class="dropdown-item text-danger" href="/delete/{{ drug.drug_id }}" data-title="Delete" data-toggle="modal" data-target="#delete"><span class="fas fa-trash-alt mr-2"></span>Remove</a>
        </div>
    </div>
</td>

Я только что начал строить проект на Django и из всех CRUD шаблонов этот мне кажется наиболее упрощенным. До этого я пробовал модуль DeleteView, object.save() после удаления, проверку моего html, ... к сожалению, никаких сообщений об ошибках не выскакивало.

Вы можете показать мне способ решения этой проблемы?

Вы не должны сохранять препарат, поскольку тогда вы снова создаете новую запись с теми же элементами:

def destroy(request, drug_id):
    d = Drug.objects.get(drug_id=drug_id)
    d.delete()  
    # no d.save()
    return redirect('/')

Кроме того, вы должны создавать, обновлять и удалять сущности с помощью POST-запроса, а не GET-запроса: GET-запросы должны быть безопасными.

Вы можете ограничить доступ к представлению с помощью @require_POST [Django-doc]:

from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST

@require_POST
def destroy(request, drug_id):
    d = get_object_or_404(Drug, drug_id=drug_id)
    d.delete()
    return redirect('/')

и использовать мини-форму на HTML-странице вместо ссылки:

<form method="POST" action="/delete/{{ drug.drug_id }}/">
    <button type="submit" class="dropdown-item text-danger"><span class="fas fa-trash-alt mr-2"></span>Remove</button>
</form>

Не сохраняйте данные после удаления объекта, потому что если вы сохраните эти данные, они будут создаст те же данные в новом 'id'. Попробуйте это, Это сработает...

def destroy(request, drug_id):  
    d = Drug.objects.get(drug_id=drug_id)  
    d.delete()
    return redirect("/") 

Совместив с первым ответом от @Willem Van Onsem, я изменил путь к urls.py для уничтожения функции следующим образом:

path('delete/<str:drug_id>/', destroy)

с заменой int на string и включением слеша / в конце url

Вернуться на верх