After clicking on "confirm" in my organism_delete.html form, I used to be redirected back to the list of organisms (organism_list.html template) as specified in the view. But now I get a 404 error instead.
Page not found (404) Request Method: GET Request URL: http://localhost:8000/library/organisms/ABC1233/delete/post?csrfmiddlewaretoken=Rdk575IEp5bbvrriJ1szlYNjmq8V1DvuYzNWEWz07s78IJSal9foHdkvxwcimIEp
Using the URLconf defined in itslibrary.urls, Django tried these URL patterns, in this order: admin/ accounts/ [name='home']
library/ organisms/ [name='organism_list'] library/ organisms/new/ [name='organism_new']
library/ organisms/ [name='organism_detail'] library/ organisms//update/ [name='organism_update']
library/ organisms//delete/ [name='organism_delete']
^media/(?P.*)$ The current path, library/organisms/ABC1233/delete/post, didn’t match any of these.
Two things that stand out to me is first that the error says it's a GET request, not a POST as the form specifies. And second is why is it trying to get to .../delete/post...?
It might be important to know that I changed my model and added "Primary Key = True" to a unique CharField, and I've been modifying the rest of the app to match that. It may not be related because I can list the organisms and I can get to the delete page, I just can't submit it.
I don't know how to debug this, it seems to be hidden behind the Django magic, any guidance will be very appreciated.
Code below:
Models.py:
#Organism
class Organism(models.Model):
genbank = models.CharField(max_length = 10, primary_key=True, unique=True)
genus = models.CharField(max_length = 50)
species = models.CharField(max_length = 50)
strain = models.CharField(max_length = 50)
organism_sequence = models.TextField()
created_at = models.DateTimeField(auto_now_add = True)
fasta = models.FileField(upload_to='organism_fasta/', null=True, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_NULL, null=True)
def __str__(self):
return self.genus[:10] ', ' self.species[:10] ', ' self.strain[:10]
def get_absolute_url(self):
return reverse('organism_detail', args=[str(self.genbank)])
#Motif
class Motif(models.Model):
organism = models.ForeignKey('Organism', on_delete = models.CASCADE, related_name= "motifs")
region_name = models.CharField(max_length = 15, choices = MOTIF_CHOICES)
motif_sequence = models.CharField(max_length = 600)
structure_image = models.ImageField(upload_to='structures/', blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add = True)
def __str__(self):
return self.region_name[:10]
app urls.py
urlpatterns = [
path('organisms/', views.OrganismListView.as_view(), name='organism_list'),
path('organisms/new/', views.OrganismCreateView.as_view(), name='organism_new'),
path('organisms/<pk>', views.OrganismDetailView.as_view(), name='organism_detail'),
path('organisms/<pk>/update/', views.OrganismUpdateView.as_view(), name='organism_update'),
path('organisms/<pk>/delete/', views.OrganismDeleteView.as_view(), name='organism_delete'),
]
Delete View in views.py:
#Delete
class OrganismDeleteView(LoginRequiredMixin, DeleteView):
model = Organism
success_url = '/library/organisms'
template_name = 'library/organism_delete.html'
login_url = "/login"
organism_delete.html template
{% extends "base.html" %}
{% block content %}
<form action="post">
{% csrf_token %}
<p>Are you sure you want to delete {{organism.genus}} {{organism.species}} {{organism.strain}}?</p>
<p>This cannot be undone!</p>
<input type="submit" value="confirm"/>
</form>
{% endblock content %}
CodePudding user response:
The method="…"
of the form is "POST"
, not the :action="…"
<form method="post"> {% csrf_token %} <p>Are you sure you want to delete {{organism.genus}} {{organism.species}} {{organism.strain}}?</p> <p>This cannot be undone!</p> <input type="submit" value="confirm"/> </form>
It might be better to work with reverse_lazy(…)
[Django-doc] to determine the path of the success_url
:
from django.urls import reverse_lazy
class OrganismDeleteView(LoginRequiredMixin, DeleteView):
model = Organism
success_url = reverse_lazy('organism_list')
template_name = 'library/organism_delete.html'
login_url = '/login'
CodePudding user response:
When you do <form action="post" ...
, you are asking the form to "append post
to the current URL, using a GET request, and go the endpoint with 'your data'".
More details here: https://www.w3schools.com/tags/att_form_action.asp
I am not sure how will you manage to make the page call again the same page (maybe omit action="..."
, but you should add (change) method="..."
; from the implicit method="get"
, make it a method="post"
instead.
Without being a django connoisseur myself, it would be nice if you could "easily" teach django to listen to the method="delete"
instead of POST
, as it will make your API a tad more semantic.