如何在 Django 中添加对评论的回复?
Posted
技术标签:
【中文标题】如何在 Django 中添加对评论的回复?【英文标题】:How to make add replies to comments in 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 文件中添加回复“按钮”。请帮助告诉我可以做哪些更改来制作带有回复的简单评论框。非常感谢
【问题讨论】:
我可以推荐这个工具:disqus.com 【参考方案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)
记得运行makemigrations
和migrate
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 或其他框架就无法做出此回复?我认为我越来越复杂,任务很简单,只需添加对 cmets 的回复 :(【参考方案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="#collapseExamplecomment.id" role="button" aria-expanded="false" aria-controls="collapseExample">
Reply </a>
<div class="collapse" id="collapseExamplecomment.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 %
【讨论】:
非常感谢这对您有很大帮助。只是想指出崩溃可能不会立即生效。但可以很容易地调整或移除。非常有帮助的答案。谢谢! 不客气。我很高兴它对您有所帮助。以上是关于如何在 Django 中添加对评论的回复?的主要内容,如果未能解决你的问题,请参考以下文章