Submit button in template leading to HTTP ERROR 405

Submitted 3 years, 11 months ago
Ticket #8
Views 306
Language/Framework Django
Priority Low
Status Closed

I am adding a comment section for my posts, the issue is after submitting it leads to HTTP ERROR 405 This is the first time to receive this error, I have reviewed the views several times but I think the error might be from the views.py in post detail view

class PostDetailView(DetailView):
    model = Post
    template_name = "post_detail.html"

    def get_context_data(self, *args, **kwargs):
        context = super(PostDetailView, self).get_context_data()
        post = get_object_or_404(Post, slug=self.kwargs['slug'])
        comments = Comment.objects.filter(post=post).order_by('-id')
        total_likes = post.total_likes()
        liked = False
        if post.likes.filter(id=self.request.user.id).exists():
            liked = True

        if self.request.method == 'POST':
            comment_form = CommentForm(self.request.POST or None)
            if comment_form.is_valid():
                content = self.request.POST.get('content')
                comment = Comment.objects.create(
                    post=post, user=request.user, content=content)
                comment.save()
                return HttpResponseRedirect("post_detail.html")
        else:
            comment_form = CommentForm()

        context["total_likes"] = total_likes
        context["liked"] = liked
        context["comments"] = comments
        context["comment_form"] = comment_form
        return context

here is the template


            <div class="main-comment-section">
            {{comments.count}} Comment{{comments|pluralize}}
            {% for comment in comments %}
            <blockquote class="blockquote">
                <p class="mb-0"> {{ comment.content}}</p>
                <footer class="blockquote-footer">by<cite title="Source Title">{{comment.user| capfirst}}</cite></footer>
            </blockquote>
            {% endfor %}

here are the comments models.py

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField(max_length=160)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '{}-{}'.format(self.post.title, str(self.user.username))
Submitted on May 25, 20
add a comment

2 Answers

Verified

where is the form submission? .. what is your initial analysis on this?

Submitted 3 years, 11 months ago

I have been trying to follow the logic of a function to be implemented in my classed view

- ahmed.hisham87 3 years, 11 months ago

if you still want to stick with this approach , lets add print statement here if self.request.method == 'POST': comment_form = CommentForm(self.request.POST or None) if comment_form.is_valid(): content = self.request.POST.get('content') comment = Comment.objects.create( post=post, user=request.user, content=content) comment.save() print('Its working') return HttpResponseRedirect("post_detail.html")

- Vengat 3 years, 10 months ago

any update on this?

- Vengat 3 years, 10 months ago

it did not print

- ahmed.hisham87 3 years, 10 months ago

Method Not Allowed (POST):

- ahmed.hisham87 3 years, 10 months ago

exactly as its DetailedView, its not allowing to POST, as i mentioned above, can you use different view for POST the comment

- Vengat 3 years, 10 months ago

how do you suggest to do it?

- ahmed.hisham87 3 years, 10 months ago

create another function based view & submit the comment over there and redirect to whatever the page you like to

- Vengat 3 years, 10 months ago

or try this ```def post(self, request, args, *kwargs): form = CommentForm(request.POST, request.FILES) if form.is_valid(): # Write Your Logic here

    self.object = self.get_object()
    context = context = super(Detail, self).get_context_data(**kwargs)
    context['form'] = CommentForm
    return self.render_to_response(context=context)

else:
    self.object = self.get_object()
    context = super(Detail, self).get_context_data(**kwargs)
    context['form'] = form
    return self.render_to_response( context=context)```
- Vengat 3 years, 10 months ago

if you still want to stick with DetailView itself then use above logic

- Vengat 3 years, 10 months ago

i hope this one fix your issue

- Vengat 3 years, 10 months ago

I am getting somewhere but I got Exception Value: post() got an unexpected keyword argument 'slug'

- ahmed.hisham87 3 years, 10 months ago

I am getting somewhere but I got Exception Value: post() got an unexpected keyword argument 'slug'

- ahmed.hisham87 3 years, 10 months ago

show me the code?

- Vengat 3 years, 10 months ago

I think this is right ``` def get_context_data(self, args, *kwargs): context = super(PostDetailView, self).get_context_data() post = get_object_or_404(Post, slug=self.kwargs['slug']) comments = Comment.objects.filter(post=post).order_by('-id') total_likes = post.total_likes() liked = False if post.likes.filter(id=self.request.user.id).exists(): liked = True

    if self.request.method == 'POST':
        comment_form = CommentForm(self.request.POST or None)
        if comment_form.is_valid():
            content = self.request.POST.get('content')
            comment = Comment.objects.create(
                post=post, user=self.request.user, content=content)
            comment.save()
            return HttpResponseRedirect("post_detail.html")
    else:
        comment_form = CommentForm()

    context["total_likes"] = total_likes
    context["liked"] = liked
    context["comments"] = comments
    context["comment_form"] = comment_form
    return context

def post(self, request, args, *kwargs):
    form = CommentForm(request.POST, request.FILES)
    if form.is_valid():  # Write Your Logic here
        self.object = self.get_object()
        context = context = super(
            PostDetailView, self).get_context_data(**kwargs)
        context['form'] = CommentForm
        return self.render_to_response(context=context)
    else:
        self.object = self.get_object()
        context = super(PostDetailView, self).get_context_data(**kwargs)
        context['form'] = form
        return self.render_to_response(context=context)

```

- ahmed.hisham87 3 years, 10 months ago

so you are able to render the detail view but not able to POST right?

- Vengat 3 years, 10 months ago

no I am getting post() got an unexpected keyword argument 'slug' with a wrong url http://127.0.0.1:8000/score/score/hthththt76/

- ahmed.hisham87 3 years, 10 months ago

I quickly reproduce the logic , see below its perfectly working to me. you can check at your end with slight change instead id, it should be slug, class DetailPostView(DetailView): model = Post template_name = 'tutorial/tutorial_detail.html' fields = ['title']

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # favorite = Favorite.objects.filter(add_favorite=True)
        form = CommentForm(self.request.POST or None)
        id = self.kwargs['pk']
        obj_post = Post.objects.get(id=id)
        context['form'] = form
        return context

    def post(self, request, *args, **kwargs):
        form = CommentForm(request.POST, None)
        if form.is_valid():
        # Write Your Logic here
            print('Its Saved')
            self.object = self.get_object()
            context = super(DetailPostView, self).get_context_data(**kwargs)
            return self.render_to_response(context=context)
- Vengat 3 years, 10 months ago

I have followed your logic and amended somethings : The views: ``` class PostCommentCreateView(CreateView): model = Comment fields = ['content']

def get(self, request, slug, *args, **kwargs):
    raise Http404

def post(self, request, slug, *args, **kwargs):
    self.post = Post.objects.get_or_404(slug=slug) <-----Error 'Manager' object has no attribute 'get_or_404'
    self.user = request.user

    super().post(request, *args, **kwargs)

def form_valid(self, form):
    form.instance.post = self.post
    form.instance.user = self.user
    return super(PostCommentCreateView, self).form_valid(form)

Here is the urls: path('post/<slug:slug>/comment', PostCommentCreateView.as_view(), name='post-comment'), here is the template: <form action={% url 'score:post-comment' post.slug %} method="post" class="comment-form" action=".">
{% csrf_token %} {{ comment_form.as_p }} {% if request.user.is_authenticated %} <input type="submit" value="Submit" class="btn btn-outline-success"> {% else %} <input type="submit" value="Submit" class="btn btn-outline-success" disabled> You must be Logged in to Comment {% endif %} </form> ```

- ahmed.hisham87 3 years, 10 months ago

why you are sending slug to POST.. see if its POST request then you just need to save the data using the form just like below def post(self, request, args, *kwargs): form = TaskForm(request.POST, None) if form.is_valid(): new_form = form.save(commit=False) new_form.user = request.user new_form.save()

    return redirect('/todo/')
- Vengat 3 years, 10 months ago

still not working I've tried everything

- ahmed.hisham87 3 years, 10 months ago

then may be i will setup a meeting sometime tomorrow. I am pretty sure, you are missing something in your code.

- Vengat 3 years, 10 months ago

that will be great

- ahmed.hisham87 3 years, 10 months ago

Can we connect around 5.30 PM PST today?

- Vengat 3 years, 10 months ago

sure

- ahmed.hisham87 3 years, 10 months ago

Awesome ..will send you the invite

- Vengat 3 years, 10 months ago

sorry i have to postponed the meeting.. how about 7 PM PST or we can connect tomorrow?

- Vengat 3 years, 10 months ago

I am ok with 7 PM PST

- ahmed.hisham87 3 years, 10 months ago

sent you the invite

- Vengat 3 years, 10 months ago

Thank you for this solution really appreciate it ``` class PostCommentCreateView(LoginRequiredMixin, CreateView): model = Comment fields = ['content', ] success_url = reverse_lazy('score:post-detail')

def post(self, request, *args, **kwargs):
    form = CommentForm(request.POST)
    if form.is_valid():
        post = form.save()
        post.save()
    print(args, kwargs, request.POST)
    return redirect('score:post-detail', slug=kwargs['slug'])

```

- ahmed.hisham87 3 years, 10 months ago

Welcome. As you can always support us Donate . If you want :)

- Vengat 3 years, 10 months ago

here is the template

{% csrf_token %} {{ comment_form.as_p }} {% if request.user.is_authenticated %} {% else %} You must be Logged in to Comment {% endif %}
{{comments.count}} Comment{{comments|pluralize}} {% for comment in comments %}

{{ comment.content}}

by{{comment.user| capfirst}}
{% endfor %}

Submitted 3 years, 11 months ago

right way to submit the comment form to different views not to same Detailed view. That is not recommended one

- Vengat 3 years, 11 months ago


Latest Blogs