【问题标题】:How to make add replies to comments in Django?如何在 Django 中添加对评论的回复?
【发布时间】:2017-12-03 21:34:06
【问题描述】:

我正在使用 Django 制作自己的博客,并且已经制作了评论系统。我想为每条评论添加回复(就像普通评论框一样),但我不知道该怎么做这是我目前的models.py cmets:

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    text = models.TextField()
    created_date = models.DateField(auto_now_add=True)
    parent = models.ForeignKey('self', null=True, related_name='replies')

    def __str__(self):
        return self.text

这是我使用 cmets 的 .html

  {% for comment in post.comments.all %}
 <ul>
  {{ comment.text }}
  {% for reply in comment.replies.all %}
      <li>
          {{ reply.text }}
      </li>
  {% endfor %}
 <ul>
 {% endfor %}

显然它正在工作,但是当我尝试在 Django 的管理站点中发表评论时,它迫使我为每条评论添加一个“父母”(这不是强制性的,因为不是每条评论都是回复)我也不知道如何在 HTML 文件中添加回复“按钮”。请帮助告诉我可以做哪些更改来制作带有回复的简单评论框。非常感谢

【问题讨论】:

标签: python html django comments


【解决方案1】:

我遇到了同样的问题,解决方法如下:

1。 对于上面提到的管理站点,只需为父字段设置blank=True。我的评论模型:

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)
  • 记得运行makemigrationsmigrate

2.让我们从视图开始。我正在使用post_detail 查看以显示帖子及其 cmets。我们添加了一个 QuerySet 来检索这篇文章的所有父活动 cmets。之后,我们使用表单的is_valid() 验证提交的数据。如果表单有效,我们检查提交的数据是否来自重播按钮表单中的隐藏输入。接下来,如果parent_id 退出,我们为重播评论创建父对象(parent_obj)和replay_comment 对象,然后我们将parent_obj 分配给replay_comment。 如果parent_obj 等于None,我们只需通过创建new_comment 对象并将其保存到数据库来继续进行正常注释。

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})

简单的评论表单:

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

* 更多关于ModelForm

最后是模板。我们需要创建两个表单。一种用于 cmets,另一种用于重放。这里有简单的模板:

<!-- 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 %}

只需添加一些漂亮的 css 和 jquery 即可淡入回复 cmets ,仅此而已。

【讨论】:

  • 父模型字段的作用是什么,请您解释一下。
【解决方案2】:

第一个问题:必须在admin中设置parent。

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

blank=True可以让你在admin中不设置parent。

第二个问题:动态添加评论。

<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)

【讨论】:

  • 您好,谢谢您的回答,但是没有 ajax 或其他框架就无法做出此回复?我认为我越来越复杂,任务很简单,只需添加对 cme​​ts 的回复 :(
【解决方案3】:

models.py

class Comment(models.Model):
    author = models.CharField(max_length=100)
    comment_field = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True)
    post = models.ForeignKey('Post', on_delete=models.CASCADE)
    reply = models.ForeignKey('Comment', on_delete=models.CASCADE, related_name="replies", null=True)

    def __str__(self):
        return self.author

views.py

def post_detail(request, slug):
    post = Post.objects.get(slug=slug)
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            reply_obj = None
            try:
                reply_id = int(request.POST.get('reply_id'))
            except:
                reply_id = None
            if reply_id:
                reply_obj = Comment.objects.get(id=reply_id)

            author = form.cleaned_data['author']
            comment = form.cleaned_data['comment']
            if reply_obj:
               Comment(author=author,comment_field=comment, reply=reply_obj, post=post).save()
            else:
                Comment(author=author,comment_field=comment, post=post).save()
            return redirect(reverse('post_detail', args=[post.slug]))
    else:
        form = CommentForm()
    comments = Comment.objects.filter(post=post, reply=None).order_by('-date_created')
    context = {
        'post':post,
        'form':form,
        'comments':comments
    }
    return render(request, 'post_detail.html', context)

模板(post_detail.html)

{% for comment in comments %}
    {{comment.author}}
    {{comment.date_created.date}}
    {{comment.comment_field}}
    
        {% for reply in comment.replies.all %}
            {{reply.author}}
            {{reply.date_created.date}}
            {{reply.comment_field}}
        {% endfor %}
        <a class="text-decoration-none" data-bs-toggle="collapse" href="#collapseExample{{comment.id}}" role="button" aria-expanded="false" aria-controls="collapseExample">
            Reply </a>
        <div class="collapse" id="collapseExample{{comment.id}}">
            <div>
                <form action="" method="POST" enctype="multipart/form-data">
                    {% csrf_token %}
                            <div class="form-group">
                                {{ form.author }}
                            </div>
                            <div class="form-group mt-md-2">
                                {{form.comment}}
                            </div>
                            <input type="hidden" name="reply_id" value="{{ comment.id }}">
                            <button class="btn btn-primary mt-md-1" type="submit" value="Reply">Reply</button>              </form>
            </div>
        </div>
    <hr>
{% endfor %}

【讨论】:

  • 非常感谢这对您有很大帮助。只是想指出崩溃可能不会立即生效。但可以很容易地调整或移除。非常有帮助的答案。谢谢!
  • 不客气。我很高兴它对您有所帮助。
猜你喜欢
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-06
相关资源
最近更新 更多