【多级评论的实现】
我这里的多见评论,我通过Django 的mptt 插件来实现的。具体一步步来吧!
【安装mptt】
pip3 install django-mptt
【将django-mptt
添加到INSTALLED_APPS
里】
INSTALLED_APPS = (
'mptt',
)
【评论模型改成mptt类】
from mptt.fields import TreeForeignKey #MPTT from mptt.models import MPTTModel #mptt
class Comment_post(MPTTModel):
text = RichTextUploadingField(verbose_name='评论内容')
post_title = models.ForeignKey(Post,verbose_name='关联文章',on_delete=models.DO_NOTHING)
comment_time = models.DateTimeField(verbose_name='评论时间',auto_now_add=True)
comment_author = models.ForeignKey(User,verbose_name='评论人',on_delete=models.DO_NOTHING)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children',db_index = True,on_delete=models.DO_NOTHING)
def __str__(self):
return self.text
class Meta: # 后台管理显示汉字,这里必须用Meta
ordering = ['-comment_time'] #按评论时间倒序排列
verbose_name = '评论管理'
verbose_name_plural = verbose_name
创建评论模型,需要继承MPTTModel,并且必须要有一个parent
字段
由于继承MPTTModel
,评论模型就有了level
,lft
, rght
和tree_id
字段,这些字段是MPTT
算法所使用的,一般不会用到!
【迁移数据库】
python manage.py makemigrations
python manage.py migrate
【前端页面显示】
在blog/post_read.html
里直接使用recursetree
标签,就能将评论全部显示出来了
recursetree
标签里,会添加两个上下文变量node
和children
node
是一个MPTT
模型对象.children
是一个变量,持有node
节点的子节点的HTML
recursetree
标签会遍历所有根节点,再对根节点的子节点进行递归处理
下面代码中的 commnets 是视图里获取的该文章的所有评论,前面我们已经是这样的,直接用就可以了
#获取这篇文章的评论,并传递到前端 #commnets=Comment_post.objects.filter(post_title=post_id).all()
{% if commnets %} {% load mptt_tags %} <dl id="comments"> {% recursetree commnets %} <dt id="{{ node.id }}"> {{ node.comment_time }} - {{ node.comment_author }} <a href="{% url 'huifu' node.id post.id %}">回复</a> </dt> <dd> <p>{{ node.text|safe }}</p> </dd> {% if not node.is_leaf_node %} <dl class="children" style="margin-left: 40px"> {{ children }} </dl> {% endif %} {% endrecursetree %} </dl> {% else %} <p class="help-block">暂无评论,欢迎发表意见!</p> {% endif %}
【子级回复的设置】
1.建一个连接展示子级回复处理视图的url,放在回复两字的链接下,并将文章id,父级ID传过去
path('huifu/<int:is_who_id>/<int:wenzhang_id>',comment_post_two,name='huifu'), #文章回复路由
2.前端展示评论哪里的回复两字 看看改没
<a href="{% url 'huifu' node.id post.id %}">回复</a> node.id 就要回复的上级ID
3.建立展示回复窗口额视图
@login_required #登录装饰器 #评论的回复页面展示视图 def comment_post_two(request,wenzhang_id,is_who_id): comment_post = CommentForm(initial={'post_title':wenzhang_id,'parent':is_who_id,'comment_author':request.user.id}) return render(request,'comments/pinglun.html',{'comment_post':comment_post})
对验证表单:CommentForm 添加一个字段
class CommentForm(forms.Form): parent=forms.CharField(widget=forms.HiddenInput())
通过comment_post = CommentForm(initial={'post_title':wenzhang_id,'parent':is_who_id,'comment_author':request.user.id})将必要默认内容传过去,生成默认值,因为隐藏,用户是看不到的
4.建立comments/pinglun.html 页面
<div class="form-group"> <form method="post" class="form-horizontal" action="{% url 'huifutijiao' %}" > <div class="col-sm-offset-1 col-sm-11"> {% csrf_token %} {{ comment_post }} <button type="submit" class="btn btn-primary">提交</button> </div> </form> </div>
5.建立回复提交处理视图
@login_required def comment_post_three(request): if request.method == 'POST': comment = CommentForm(request.POST) if comment.is_valid(): post_title = int(comment.cleaned_data['post_title']) text = comment.cleaned_data['text'] comment_author = int(comment.cleaned_data['comment_author']) parent = int(comment.cleaned_data['parent']) post = Post.objects.get(id=post_title) if post: author = User.objects.get(id=comment_author) if author: com_post = Comment_post() com_post.post_title = post com_post.text = text com_post.comment_author = author com_post.parent_id = parent com_post.save() return HttpResponse('chenggong') else: return HttpResponse('shibai1') else: return HttpResponse('shibai2')
6.建立连接这个视图的路由
path('huifutijiao/',comment_post_three,name='huifutijiao') #文章回复tijiao路由
7.看看提交的路径是不是正确
comments/pinglun.html 页面
<div class="form-group"> <form method="post" class="form-horizontal" action="{% url 'huifutijiao' %}">
【主评论表单优化】
因为我们的表单新加了
parent=forms.CharField(widget=forms.HiddenInput())
在表单选人的时候,不传递默认值的话,就过不了验证,因此我们补一个字符串过去,但在存的时候,让parent为空!
#实例评论窗口 comment_Form = CommentForm(initial={'comment_author':request.user.id,'post_title':post_id,'parent':'Null'})
完成!
【回复后的跳转问题】
用户点击回复完成后,自动调回到当前页面:
1.在回复连个字的链接下新加一个get传递url
<a href="{% url 'huifu' node.id post.id %}?next={{ request.get_full_path }}">回复</a>
2.并且进行登录判断,如果没登录,就不现实回复两字
{% if request.user.is_authenticated %} <a href="{% url 'huifu' node.id post.id %}?next={{ request.get_full_path }}">回复</a> {% else %} <tr><a href="{% url 'login' %}?next={{ request.get_full_path }}">登录可回复</a></tr> {% endif %}
3.在展示回复窗口的视图获取到url并传递到前端
@login_required
#评论的回复页面展示视图
def comment_post_two(request,wenzhang_id,is_who_id):
post_urls = request.GET.get('next') # 获取url上携带的来源地址,用于登录后跳转回去!
comment_post = CommentForm(initial= {'post_title':wenzhang_id,'parent':is_who_id,'comment_author':request.user.id})
return render(request,'comments/pinglun.html',{'comment_post':comment_post,'post_urls':post_urls})
4.前端隐藏接收并传回 pinglun.html
<input type="hidden" name="post_urls" class="form-control" placeholder="跳转隐藏了的" value="{{ post_urls}}">
5.POST处理视图,接收到,完成后重定向
post_urls = request.POST['post_urls']
#跳转或来之前的页面,如果获取不到,就重定向到首页 return redirect(post_urls,reverse('index'))
0
登陆后方可评论