Posting comment gives HTTP error 405

Hi.

I’m using Class Based Views, and I try to view details of a file, comments, and a comment submit form.

This is how the views are built:

class DicomFileDetailView(LoginRequiredMixin, DetailView):
    model = DicomFile
    template_name = 'dicoms/dicomfile_detail.html'
    context_object_name = 'dicomfile'

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # Add extra context from another model
        context['comment_form'] = CommentForm()
        return context

   

class CommentSubmit(SingleObjectMixin, FormView):
    model = DicomFile
    form_class = CommentForm
    template_name = 'dicoms/dicomfile_detail.html'

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super().post(request, *args, **kwargs)

    def get_form_kwargs(self):
        kwargs = super(CommentSubmit, self).get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs

    def form_valid(self, form):
        comment = form.save(commit=False)
        comment.dicom_file = self.object
        comment.save()
        return super().form_valid(form)

This is how the urls.py looks like:

app_name = 'dicoms'

urlpatterns = [
    path('upload/',views.DicomFileUploadView.as_view(),name='dicom_upload'),
    path('my-uploads/',views.DicomFileMyUploadsListView.as_view(),name='dicom_my_uploads_list'),
    path('shared/',views.DicomFileMyUploadsListView.as_view(),name='dicom_shared_list'),
    path('details/<int:pk>/',views.DicomFileDetailView.as_view(),name='dicom_detail'),
    path('details/<int:pk>/',views.CommentSubmit.as_view(),name='post_comment'),
    path('delete/<int:pk>/', views.DicomFileDeleteView.as_view(),name='dicom_delete'),
    ]

Comment model looks like this:

class Comment(models.Model):
    author = models.ForeignKey('users.User', on_delete=models.CASCADE, null=True, blank=False)
    dicom_file = models.ForeignKey('DicomFile', on_delete=models.CASCADE, null=True, blank=False)
    comment = models.TextField(blank=False)
    comment_time = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['comment_time']

Commen form looks like this:

class CommentForm(forms.ModelForm):

    class Meta:
        model = Comment
        fields = ('comment',)

    def __init__(self, *args, **kwargs):
        """Save the request with the form so it can be accessed in clean_*()"""
        self.request = kwargs.pop('request', None)
        super(CommentForm, self).__init__(*args, **kwargs)

And this is how the template ‘dicomfile_detail.html’ looks like:

{% extends 'base.html' %}

{% block title %}

DICOM file details

{% endblock %}

{% block content %}

<h1>Details for Dicom File</h1>

<br>Uploaded by: <a href="{% url 'users:user_detail' pk=dicomfile.owner.id %}">{{dicomfile.owner.get_full_name}}</a>

<br>Modality: {{dicomfile.modality}}

<h3> Shared with: </h3>

{{dicomfile.access.all}}

<h3> Add comment: </h3>

<form action="{% url 'dicoms:dicom_detail' pk=dicomfile.id %}" method="POST">

    {% csrf_token %}

    {{comment_form.as_p}}

    <input type="submit" value='SUBMIT'>

</form>

<h3> Comments: </h3>

{% for comment in dicomfile.comment_set.all %}

<p>

<br><a href="{% url 'users:user_detail' pk=comment.author.id %}">{{comment.author.get_full_name}}</a>  Date: {{comment.comment_date}}

<br>{{comment.comment}}

</p>

{% endfor %}

{% endblock %}

The comment form is visible, the detail page is working. But when I write a comment and submit the form, I just get the same url with an error like: HTTP ERROR 405

In the terminal this is what I get:

[11/Apr/2022 07:35:19] "GET /images/details/7/ HTTP/1.1" 200 3902
Method Not Allowed (POST): /images/details/7/
Method Not Allowed: /images/details/7/
[11/Apr/2022 07:35:22] "POST /images/details/7/ HTTP/1.1" 405 0

The desired solution is to make logged in users comment on DICOM files. In the database the comment object sohuld be saved with the logged in user as auther, and the DICOM file it’s commented on as dicom_file field.

I have searched online but I didn’t found out why it’s not working. Why it’s not working? How can I fix that?

I don’t think it’s ever going to views.CommentSubmit because it will always go to the first path.

path('details/<int:pk>/',views.DicomFileDetailView.as_view(),name='dicom_detail'),
path('details/<int:pk>/',views.CommentSubmit.as_view(),name='post_comment'),

Your paths are the same (unless the parent urls.py allows you to differentiate them). So Django just picks the first match in terms of pattern.

Something like would help to fix it I think:

path('details/<int:pk>/',views.DicomFileDetailView.as_view(),name='dicom_detail'),
path('details/<int:pk>/post-comment/',views.CommentSubmit.as_view(),name='post_comment'),

and also in your view(s):

class CommentSubmit(...):
    <snip>
    http_method_names = ['get', 'post']
    <snip>

Depending on your setup, you want your nginx/apache/whatever to also not block the HTTP POST method.

See: 405 Method Not Allowed - HTTP | MDN

In fact, I think what happens is that your request hits dicom_detail, which does not allow the POST method.