Django/Python - Delete function in UpdateView is duplicating rather than deleting
i have created a Django app that allows users to enter their stock trades, as a journaling tool. When a user clicks on an individual journal entry from the index page, they will be taken to a detail page showing all the information on that individual entry (single_entry.html). This page is handled by an UpdateView. From this page, a user can edit/update any info, as well as DELETE that specific entry. To accomplish this, I've imported the DeletionMixin module from django.views.generic.edit.
However, when I click on the "Delete" button in the form, the entry is duplicated instead of deleted! Does anyone know why that's happening?? Thanks for your help!
Here's my class based view in views.py:
class SingleEntryView(UpdateView):
template_name = "single_entry.html"
model = Entry
fields = ['ticker', 'strategy', 'result', 'comments', 'image']
success_url = '/'
def post(self, request, *args, **kwargs):
if "delete_button" in self.request.POST:
return self.delete(request, *args, **kwargs)
def update_post(self, form, pk):
if "update_button" in self.request.POST:
form.instance.user = self.request.user
return super(SingleEntryView, self).update_post(form)
single_entry.html:
{% extends 'base.html' %}
{% block title %}
Trading Journal - Entry
{% endblock title %}Trading Journal
{% block content %}
<form method="POST" action="/">
{% csrf_token %}
{% for field in form %}
{{field.label_tag}}
{{field}}
{% if field.errors %}
<small class="error">{{ field.errors|striptags }}</small>
{% endif %}
{% endfor %}
<button type="submit" name="update_button">Save</button>
<button type="submit" name="delete_button">Delete</button>
</form>
<img src="{{ entry.image.url }}" alt="{{ entry.result }}">
{% endblock content %}
urls.py:
from django.urls import path
from django.contrib import admin
from . import views
urlpatterns = [
path("", views.EntryView.as_view()),
path("entries/<int:pk>/", views.SingleEntryView.as_view(), name="single-entry"),
path("admin/", admin.site.urls)
]
Asking ChatGPT for help, it recommended the follwing code in my UpdateView(which gave me the same problem):
def post(request, self, form):
print("post request")
print("request.post", request.POST)
if "delete" in request.POST:
print("delete found")
return self.delete_entry()
else:
print("else statement")
#return super(SingleEntryView, self).post(request, form)
return super().post(request, form)
#return super().post(request, *args, **kwargs)
def delete_entry(self):
entry = self.get_object()
print("get object")
entry.delete()
messages.success(self.request, "Your entry was deleted successfully.")
return redirect("/")
In your code, looks like you are trying to handle the deletion of the entry within the post()
method of your SingleEntryView
class. But the DeleteView
provided by Django already handles the deletion logic, so you don't need to override the post()
method for deletion. Now modify your code like this :
from django.urls import reverse_lazy
from django.contrib import messages
from django.views.generic import DeleteView
class SingleEntryDeleteView(DeleteView):
model = Entry
template_name = "delete_entry.html"
success_url = reverse_lazy('index')
def delete(self, request, *args, **kwargs):
messages.success(self.request, "Your entry was deleted successfully.")
return super().delete(request, *args, **kwargs)
Now it will handle the deletion process, and entry will be deleted without duplication.
And in your single_entry.html
, you can create a link or button to the delete view, like so :
<form method="POST" action="{% url 'single-entry-delete' entry.pk %}">
{% csrf_token %}
<button type="submit">Delete</button>
</form>
Ensure you have a corresponding URL pattern in your urls.py
for the SingleEntryDeleteView
:
from django.urls import path
from .views import SingleEntryDeleteView
urlpatterns = [
path('entries/<int:pk>/delete/', SingleEntryDeleteView.as_view(), name='single-entry-delete'),
]
Now it should work fine. Happy Coding!
There are two problems here. The first one is that you do not route back to your view, you should make a POST request to the same path, so:
<!-- no action 🖟 -->
<form method="POST">
<!-- … -->
</form>
in the view, you should handle the delete scenario with self.object.delete()
:
class SingleEntryView(UpdateView):
template_name = 'single_entry.html'
model = Entry
fields = ['ticker', 'strategy', 'result', 'comments', 'image']
success_url = '/'
def post(self, request, *args, **kwargs):
if 'delete_button' in self.request.POST:
self.object.delete()
return HttpResponseRedirect(self.get_success_url())
return super().post(request, *args, **kwargs)
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Note: Since PEP-3135 [pep], you don't need to call
super(…)
with parameters if the first parameter is the class in which you define the method, and the second is the first parameter (usuallyself
) of the function.