How can I allow the user to edit comments in a Django Blog using DetailView and UpdateView on the same page?

I've been at this for a couple days and have followed a few different tutorials to get what I want. I'm pretty close....I just can't figure out how to get the user to be able to edit their comment. I've tried several different approaches...Here's what I have so far...

My Models...

class Suggestion(models.Model):
    id = models.UUIDField(default=uuid.uuid4,primary_key=True,unique=True)
    created_by = models.ForeignKey(User,null=True,on_delete=models.DO_NOTHING,related_name='suggestion_created_by')
    last_update = models.DateTimeField(editable=False,null=True)
    suggestion_creation_date = models.DateTimeField(editable=False,null=True)
    suggestion_name = models.CharField(max_length=255,null=True)
    suggestion_status = HTMLField(blank=True,null=True)
    suggestion = HTMLField(blank=True,null=True)
    unique_identifier = models.CharField(max_length=64,null=True,blank=True)

   class Meta:
        ordering = ["suggestion_name"]
    
    def __str__(self):
        return self.suggestion_name
    
    def get_absolute_url(self):
        return reverse("Suggestions:suggestion_detail",kwargs={'pk':self.pk})

class SuggestionComment(models.Model):
    author = models.ForeignKey(User,on_delete=models.CASCADE)
    comment = models.CharField(max_length=255,blank=True)
    created_on = models.DateTimeField(default=timezone.now)
    suggestion = models.ForeignKey('Suggestion',on_delete=models.CASCADE,related_name='suggestion_comments')
    upvotes = models.ManyToManyField(User,blank=True,related_name='suggestion_comment_upvotes')

    def get_absolute_url(self):
        return reverse("Suggestions:suggestion-detail", kwargs={"pk": self.suggestion.pk})

My Templates...

DetailView..

<!DOCTYPE html>
{% extends "base21.html" %}
<title>{% block title %} LevelSet Suggestion By Name Detail {% endblock %}</title>
{% block body_block %}

<div class="box12">

  <h1 class="title">{{ suggestion_detail.suggestion_name }}</h1>

  <div class="spacer281">
    {{ suggestion_detail.suggestion|safe }}
  </div>

  {% if suggestion_detail.suggestion_status != None %}

    <div class="spacer280">
        <h2>Status - </h2>
    </div>

    <div class="spacer76">
      {{ suggestion_detail.suggestion_status|safe }}
    </div>

  {% endif %}

  <div class="spacer285">
    {% include 'suggestion_comments.html' %}
  </div>

</div>

</div>

{% endblock %}

suggestion_comments.html ( Include )

    <form method='POST' class="comment-form">
      {% csrf_token %}
        <div class="spacer284">
          {{ form.comment }}
        </div>
      <button class="button7" type="submit">Submit</button>
    </form>
    <div class="spacer286">
      {% if suggestion_comments %}
        <h2>Comments</h2>
        {% for comment in object.suggestion_comments.all %}
          <div class="spacer291">
            <p><a href="{% url 'Main:associate_directory_associate_detail' pk=comment.author.id %}">{{ comment.author }}</a> {{ comment.created_on }}</p>
            <p class="spacer290">{{ comment.comment }}</p>
              <div class="spacer289">
                <div class="upvote-comment-count">{{ comment.total_comment_upvotes }}</div>
                <button type="button" class="button6" data-href="{% url 'Suggestions:suggestion_comment_like' comment.id %}">Like</button>
                <button type="button" class="button2" data-href="">Reply</button>
                {% if comment.author == request.user %}
                  <button type="button" class="button4" id="{{ comment.id }}" pk="{{ object.pk }}" href="{% url 'Suggestions:suggestion_comment_edit' comment.id %}">Edit</button>
                  <div class="spacer159" id="hide_payment" style="display:none;">
                    <form method='POST'>
                      {% csrf_token %}
                        <div class="spacer284">
                          {{ form.comment }}
                        </div>
                      <button class="button7" type="submit">Submit</button>
                    <form>
                  </div>
                    <button type="button" class="button3" data-href="{% url 'Suggestions:suggestion_delete' comment.id %}">Delete</button>  
                {% endif %}
              </div>
            </div>
        {% endfor %}
      {% else %}
        <h2>No Comments Yet</h2>
      {% endif %}
    </div>

My Views...

class SuggestionDetailView(LoginRequiredMixin,DetailView):
    model = Suggestion
    context_object_name = 'suggestion_detail'
    template_name = 'suggestion_detail.html'

def get_context_data(self, **kwargs):
    context = super(SuggestionDetailView, self).get_context_data(**kwargs)
    form = SuggestionCommentForm()
    suggestion_comments = SuggestionComment.objects.filter(suggestion_id=self.object.pk).order_by('-created_on').all()
    context['form'] = form
    context['suggestion_comments'] = suggestion_comments
    return context

def post(self, request, *args, **kwargs):
    form = SuggestionCommentForm(request.POST)

    if form.is_valid():
        new_comment = form.save(commit=False)
        new_comment.author = request.user
        new_comment.suggestion = self.get_object()
        new_comment.save()
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        html = render_to_string('suggestion_comments.html', context, request=self.request)
        return JsonResponse({'form': html})

    else:

        form_errors = form.errors.as_json()
        response = HttpResponse(form_errors, status=400)
        response['content_type'] = 'application/json'
        return response
  • I'm using a function based view below as I couldn't figure out how to get UpdateView to work and found an example online of a function based view.....

    def suggestion_comment_edit_view(request, id):
         comment = get_object_or_404(SuggestionComment, pk=id) 
    
         if request.method == "POST":
             form = SuggestionEditCommentForm(request.POST, instance=comment)
    
             if form.is_valid():
                comment = form.save(commit=False)
                comment.save()
                return
          else:
             form = SuggestionEditCommentForm(instance=comment)
    
          return render(request, 'suggestion_comments.html', {'form': form})
    

And Here's some AJAX...

      $(document).on("click",'.button4',function(e){
        // var detail_pk = $(this).attr('pk');
        var suggestion_pk = $(this).attr('pk');
        var comment_id = $(this).attr('id');
        // console.log(detail_pk);
        // var data= $(this).serialize();
        console.log(comment_id);
        $.ajax({
            url: '/LevelSet/Suggestions/suggestion_comment_edit/'+comment_id+'/',
            type: 'get',
            success: function (data) {
                $('#hide_payment').show();
                $("#payments").after(data);
                $('#hide_payment').click(function(){
                    $("#payment_form").remove();
                    $('#hide_payment').hide();
                });
            }
        });
        });

My URLs...

path("suggestion_comment_edit/<int:id>/",views.suggestion_comment_edit_view, name='suggestion_comment_edit'),

I have actually tried to change the URL to associate it with the detailview but that didn't seem to help either...

At one point I had something like...

path("suggestion_by_name_detail/2c560fc6-f00e-455a-99ae-82b294a134d8/<uuid:pk>/<int:id>/",views.SuggestionByNameDetailView.as_view(), name='suggestion_by_name_detail'),

In order to get both the DetailView and the comment ID in the same URL but didn't seem to help.

I'm fairly certain I'm confusing a few things....This is almost giving me what I want...I am able to display the blog with the detailview..the comment at the top works just as I want it to....The issue is how to get the edit button to work....It's a bit bizarre because I can actually see it kinda working in the browser...If I click on the link in the Chrome Browser it actually shows me the comment in question edit mode....and allows me to update it there....But on the screen if I just do a {{ form )) it shows me a blank entry field....I'm open to UpdateView....I just couldn't figure it out at that point...

Should be easy with minimal edits to your existing code

Add PK into form

  • Must be an input so the HTML form will include it inside the post
    • I believe the name attr is all you really need
  • You could also submit with AJAX and include the pk from the button4 attr
{% for comment in object.suggestion_comments.all %}
  <div class="spacer291">
    <p><a href="{% url 'Main:associate_directory_associate_detail' pk=comment.author.id %}">{{ comment.author }}</a> {{ comment.created_on }}</p>
    <p class="spacer290">{{ comment.comment }}</p>
      <div class="spacer289">
        <div class="upvote-comment-count">{{ comment.total_comment_upvotes }}</div>
        <button type="button" class="button6" data-href="{% url 'Suggestions:suggestion_comment_like' comment.id %}">Like</button>
        <button type="button" class="button2" data-href="">Reply</button>
        {% if comment.author == request.user %}
          <button type="button" class="button4" id="{{ comment.id }}" pk="{{ object.pk }}" href="{% url 'Suggestions:suggestion_comment_edit' comment.id %}">Edit</button>
          <div class="spacer159" id="hide_payment" style="display:none;">
            <form method='POST'>
              {% csrf_token %}

                <div style="display:none;">
                  <input type="number" name="pk" value="{{comment.pk}}"></input>
                </div>

                <div class="spacer284">
                  {{ form.comment }}
                </div>
              <button class="button7" type="submit">Submit</button>
            <form>
          </div>
            <button type="button" class="button3" data-href="{% url 'Suggestions:suggestion_delete' comment.id %}">Delete</button>  
        {% endif %}
      </div>
    </div>
{% endfor %}

Add Logic to View to handle Edits

def post(self, request, *args, **kwargs):
    print('POST:', request.POST) # to make sure PK is being sent, Del after

    commentObj = None
    if request.POST.get('pk'):
        commentObj = SuggestionComment.objects.filter(pk=request.POST.get('pk'))

    form = SuggestionCommentForm(request.POST, instance=commentObj)

    if form.is_valid():
        new_comment = form.save(commit=False)
        new_comment.author = request.user
        new_comment.suggestion = self.get_object()
        new_comment.save()
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        html = render_to_string('suggestion_comments.html', context, request=self.request)
        return JsonResponse({'form': html})
    else:
        form_errors = form.errors.as_json()
        response = HttpResponse(form_errors, status=400)
        response['content_type'] = 'application/json'
        return response
Back to Top