Использование Django DeleteView и получение 404 после подтверждения удаления
После нажатия на кнопку "подтвердить" в форме organism_delete.html я перенаправлялся обратно в список организмов (шаблон organism_list.html), как указано в представлении. Но теперь вместо этого я получаю ошибку 404.
Страница не найдена (404) Метод запроса: GET запрос URL: http://localhost:8000/library/organisms/ABC1233/delete/post?csrfmiddlewaretoken=Rdk575IEp5bbvrriJ1szlYNjmq8V1DvuYzNWEWz07s78IJSal9foHdkvxwcimIEp
Используя URLconf, определенный в itslibrary.urls, Django попробовал эти URL шаблоны, в таком порядке: admin/ учетные записи/ [name='home']
library/ organisms/ [name='organism_list'] library/ organisms/new/ [name='organism_new']
библиотека/ организмы/ [name='organism_detail'] библиотека/ организмы//обновить/ [name='organism_update']
библиотека/ организмы//удалить/ [name='organism_delete']
^media/(?P.*)$ Текущий путь, library/organisms/ABC1233/delete/post, не совпал ни с одним из этих путей.
Две вещи, которые меня выделяют: во-первых, ошибка говорит, что это GET-запрос, а не POST, как указано в форме. И второе - почему он пытается добраться до .../delete/post...?
Возможно, важно знать, что я изменил свою модель и добавил "Primary Key = True" к уникальному полю CharField, и я изменил остальную часть приложения, чтобы соответствовать этому. Это может быть не связано, потому что я могу перечислить организмы и могу попасть на страницу удаления, я просто не могу отправить ее.
Я не знаю, как это отладить, похоже, это скрыто за магией Django, любое руководство будет очень признательно.
Код ниже:
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
{% 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" class="btn btn-danger" value="confirm"/>
</form>
{% endblock content %}
Формой method="…" является "POST", а не :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" class="btn btn-danger" value="confirm"/>
</form>
Возможно, лучше работать с reverse_lazy(…) [Django-doc] для определения пути 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'
Когда вы делаете <form action="post" ..., вы просите форму "добавить post к текущему URL, используя запрос GET, и передать конечную точку с "вашими данными"".
Более подробная информация здесь: https://www.w3schools.com/tags/att_form_action.asp
Я не уверен, как вам удастся заставить страницу снова вызывать ту же самую страницу (возможно, опустите action="...", но вы должны добавить (изменить) method="..."; из неявного method="get" сделайте method="post" вместо него.
Не будучи сам знатоком django, было бы неплохо, если бы вы могли "легко" научить django слушать method="delete" вместо POST, поскольку это сделает ваш API более семантичным.