Home > Software design >  (Django) Delete function does not remove data from database
(Django) Delete function does not remove data from database

Time:10-07

Currently I'm having a table that shows the list of drugs. This table has a delete button in every data row. When I click it, the row does not go away.

I tried the same delete syntax (in the function called 'destroy') in Django shell and it worked. I just don't understand why when I clicked on the Remove button inside the template, nothing happened, even after refreshing.

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

My guess is if the function in views.py is not at fault then could the problem lies inside my template, within the Remove button?

<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>

I have just started building a project with Django and out of all CRUD templates I find this one most simplistic. Before this, I tried the module DeleteView, object.save() after deletion, checking my html,... unfortunately no error messsage popped up for this one.

Could you show me the way to solve this?

CodePudding user response:

You should not save the drug, since then you create a new record again with the same items:

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

Furthermore you should create, update and remove entities with a POST request, not a GET request: GET requests are supposed to be safe.

You can thus restrict access to the view with the @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('/')

and use a mini form on the HTML page instead of a link:

<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>

CodePudding user response:

Don't save after delete object, because if you're save that data it'll create that same data in new 'id'. try this, It'll work...

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

CodePudding user response:

Combining with the first answer from @Willem Van Onsem, I modified my urls.py path to destroy function as:

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

with int replaced as string and included a slash / at the end of the url

  • Related