Использование 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 более семантичным.

Вернуться на верх