djangoformsviewblogs

Django forms(comments) issue


Why is it that when editing a comment, no matter which comment I try to edit, the last one added always changes?

This is my update view:

class CommentUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = BlogComment
    form_class = CommentUpdateForm
    template_name = 'talesoflnk/blog_comment_update_form.html'

    def get_context_data(self, **kwargs):
        context = super(CommentUpdateView, self).get_context_data(**kwargs)
        context['blog'] = get_object_or_404(Blog, pk = self.kwargs['pk'])
        return context
    
    def form_valid(self, form):
        blog = get_object_or_404(Blog, pk=self.kwargs['pk'])
        form.instance.author = self.request.user
        form.instance.blog = blog 
        return super(CommentUpdateView, self).form_valid(form)
    
    def get_success_url(self):
        return reverse('blog-detail', kwargs={'pk': self.kwargs['pk'],})
    
    def test_func(self):
        comment = self.get_object()
        if self.request.user == comment.author:
            return True
        return False

Path:

path('blog/<int:pk>/comment/update', views.CommentUpdateView.as_view(), name='update_comment')

And the form itself:

{% extends 'base.html' %}

{% block content %}
<p>Post your comment for: <a href="{% url 'blog-detail' blog.pk %}">{{blog.name}}</a></p>

<div class="comment-form">
    <form action="" method="post">
        {% csrf_token %}
        <table>
            {{form.as_table}}
        </table>
        <input type="submit", value="Save changes">
    </form>
</div>


{% endblock content %}

I've no idea what to do to be honest. I was trying to add <int:comment_pk> to my route path. But it doesn't work.


Solution

  • You use an UpdateView, hence it aims to update a comment with that id, so if there is a coincidence with the blog id, and a comment id, that comment is modified, which is likely not a good idea.

    You can use a CreateView that uses the pk as blog_id:

    from django.views.generic import CreateView
    
    
    class CommentCreateView(LoginRequiredMixin, CreateView):
        model = BlogComment
        form_class = CommentUpdateForm
        template_name = 'talesoflnk/blog_comment_update_form.html'
    
        def get_context_data(self, **kwargs):
            return super().get_context_data(
                **kwargs, blog=get_object_or_404(Blog, pk=self.kwargs['pk'])
            )
    
        def form_valid(self, form):
            form.instance.author = self.request.user
            form.instance.blog_id = self.kwargs['pk']
            return super().form_valid(form)
    
        def get_success_url(self):
            return reverse('blog-detail', kwargs={'pk': self.kwargs['pk']})

    Note: Since PEP-3135 [pep], you don't need to call super(…) with parameters if the first parameter is the class in which you define the method, and the second is the first parameter (usually self) of the function.