How to make add replies to comments in Django?

前端 未结 2 1721
有刺的猬
有刺的猬 2021-02-10 14:54

I\'m making my own blog with Django and I already made a Comments system.. I want to add the replies for each comment (like a normal comment\'s box) and I don\'t know what to do

相关标签:
2条回答
  • 2021-02-10 15:41

    first Question:parent must be set in admin.

    parent = models.ForeignKey('self', null=True, blank=True, related_name='replies')
    

    blank=True can let you don't set parent in admin.

    second Question:add comment dynamicly.

    <form id="comment-form" method="post" role="form">
        {% csrf_token %}
        <textarea id="comment" name="comment" class="form-control" rows="4" placeholder="input comment!"></textarea>
        <button type="submit" class="btn btn-raised btn-primary pull-right">submit</button>
    </form>
    
        $('#comment-form').submit(function(){
        $.ajax({
            type:"POST",
            url:"{% url 'article_comments' article.en_title %}",
            data:{"comment":$("#comment").val()},
            beforeSend:function(xhr){
                xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));  
            },
            success:function(data,textStatus){
                $("#comment").val("");
                $(".comment ul").prepend(data);
            },
            error:function(XMLHttpRequest, textStatus, errorThrown){
                alert(XMLHttpRequest.responseText);
    
            }
    
        });
        return false;
    });
    

    view.py:

        print_comment = u"<p>comment:{}</p>".format(text)
        if parent:
            print_comment = u"<div class=\"comment-quote\">\
                                  <p>\
                                      <a>@{}</a>\
                                      {}\
                                  </p>\
                              </div>".format(
                                  parent.user.username,
                                  parent.text
                              ) + print_comment
        # current comment
        html = u"<li>\
                    <div class=\"comment-tx\">\
                        <img src={} width=\"40\"></img>\
                    </div>\
                    <div class=\"comment-content\">\
                        <a><h1>{}</h1></a>\
                        {}\
                        <p>{}</p>\
                    </div>\
                </li>".format(
                    img,
                    comment.user.username,
                    print_comment,
                    datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                )
    
        return HttpResponse(html)
    
    0 讨论(0)
  • 2021-02-10 15:44

    I had the same problem and resolved it as follows:

    1. For admin site as mentioned above just set blank=True for parent field. My comment model:

    class Comment(models.Model):
        post = models.ForeignKey(Post, related_name='comments')
        name = models.CharField(max_length=80)
        email = models.EmailField(max_length=200, blank=True)
        body = models.TextField()
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        # manually deactivate inappropriate comments from admin site
        active = models.BooleanField(default=True)
        parent = models.ForeignKey('self', null=True, blank=True, related_name='replies')
    
        class Meta:
            # sort comments in chronological order by default
            ordering = ('created',)
    
        def __str__(self):
            return 'Comment by {}'.format(self.name)
    
    • remember to run makemigrations and migrate

    2.Let's start with views. I'm using the post_detail view to display the post and its comments. We add a QuerySet to retrieve all parent active comments for this post. After this, we validate the submitted data using the form's is_valid(). If the form is valid we check if submitted data comes from hidden input in replay button form. Next if parent_id exits we create parent object(parent_obj) for replay comment and replay_comment object, then we assign parent_obj to replay_comment. If parent_obj is equal to None we just proceed with normal comment by creating new_comment object and saving it to the database.

    def post_detail(request, post):
        # get post object
        post = get_object_or_404(Post, slug=post)
        # list of active parent comments
        comments = post.comments.filter(active=True, parent__isnull=True)
        if request.method == 'POST':
            # comment has been added
            comment_form = CommentForm(data=request.POST)
            if comment_form.is_valid():
                parent_obj = None
                # get parent comment id from hidden input
                try:
                    # id integer e.g. 15
                    parent_id = int(request.POST.get('parent_id'))
                except:
                    parent_id = None
                # if parent_id has been submitted get parent_obj id
                if parent_id:
                    parent_obj = Comment.objects.get(id=parent_id)
                    # if parent object exist
                    if parent_obj:
                        # create replay comment object
                        replay_comment = comment_form.save(commit=False)
                        # assign parent_obj to replay comment
                        replay_comment.parent = parent_obj
                # normal comment
                # create comment object but do not save to database
                new_comment = comment_form.save(commit=False)
                # assign ship to the comment
                new_comment.post = post
                # save
                new_comment.save()
                return HttpResponseRedirect(post.get_absolute_url())
        else:
            comment_form = CommentForm()
        return render(request,
                      'core/detail.html',
                      {'post': post,
                       'comments': comments,
                       'comment_form': comment_form})
    

    Simple comment form:

    class CommentForm(forms.ModelForm):
        class Meta:
            model = Comment
            fields = ('name', 'email', 'body')
    

    * More about ModelForm

    And lastly template. We need to create two forms. One form for comments and the second one for replays. Here you have simple template:

    <!-- Comments Form --> 
    <h2>Add a new comment</h2>
    <form action="." method="post">
        {{ comment_form.as_p }}
        {% csrf_token %}
        <button type="submit">Add comment</button>
    </form>
    
    <!-- Comment with nested comments -->
    {% for comment in comments %}
        <div class="comment" style="background-color: powderblue">
            <p class="info">{{ comment.name }} | {{ comment.created }}</p>
                {{ comment.body|linebreaks }}
    
            {% for replay in comment.replies.all %}
                <p class="info">{{ replay.name }} | {{ replay.created }}</p>
                <li>{{ replay.body }}</li>
            {% endfor %}
    
            <h5>Replay</h5>
            <form action="." method="post">
                {{ comment_form.as_p }}
                {% csrf_token %}
                <!-- Hidden input for parent comment.id -->
                <input type="hidden" name="parent_id" value="{{ comment.id }}">
                <input class="btn btn-primary" type="submit" value="Replay">
            </form>
        </div>
    {% empty %}
    <h4>There are no comments yet.</h4>
    {% endfor %}
    

    just add some nice css and maybe jquery to have fade in reply comments and that's all.

    0 讨论(0)
提交回复
热议问题