Django DeleteView not make delete

Question:

I want to convert user deletion from FBV to CBV

My FBV

def delete_student(request, pk):
student = get_object_or_404(Student, pk=pk)
student.delete()

return HttpResponseRedirect(reverse("students:get_students"))

My CBV

class DeleteStudentView(DeleteView):
model = Student
form_class = StudentForm
template_name = "students/students_list.html"
success_url = reverse_lazy("students:get_students")

student_list.html

 <td><a type="button" class="btn btn-danger"
                   href="{% url 'students:delete_student' student.pk %}">Delete</a>
            </td>

There is no error, but no selection occurs. What could be the problem?

Asked By: Nikolay

||

Answers:

A DeleteView deletes with a POST or DELETE request. This is mandatory by the specs of the HTTP protocol. Your FBV is not HTTP compliant.

You thus will need to make a mini-form to do this. For example make a hidden form with:

<td><button class="btn btn-danger" onclick="delete_item({{ student.pk }});">Delete</button></td>

<!-- … -->

<form method="post" action="{% url 'students:delete_student' %}" id="delete_form">
    {% csrf_token %}
    <input type="hidden" name="pk" id="delete_pk">
</form>

<script>
function delete_item(pk) {
    var hidden_item = document.getElementById("delete_pk");
    hidden_item.value = pk;
    var form = document.getElementById("delete_form");
    form.submit();
} 
</script>

In the urls.py we define an entry for the StudentDeleteView without parameters:

# students/urls.py

from django.urls import path

app_name = 'students'

urlpatterns = [
    # …
    path('student/delete/', StudentDeleteView.as_view(), 'delete_student'),
    # …
]

In the DeleteView, you then determine the object with the primary key:

from django.shortcuts import get_object_or_404


class DeleteStudentView(DeleteView):
    model = Student
    success_url = reverse_lazy('students:get_students')

    def get_object(self, *args, **kwargs):
        return get_object_or_404(Student, pk=self.request.POST.get('pk'))

To make your function-based view HTTP compliant, you should enforce that it can only do this with a POST or DELETE request, for example with a @require_http_methods(…) decorator [Django-doc]:

from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_http_methods


@require_http_methods(["DELETE", "POST"])
def delete_student(request):
    student = get_object_or_404(Student, pk=request.POST.get('pk'))
    student.delete()
    return redirect('students:get_students')

and thus use the same "trick" with the mini-form.

Answered By: Willem Van Onsem