【小白实战】利用django2.0,搭建属于自己的博客(19)


发布时间:2019-02-15 13:08    作者: 晖哥哥   已过去:4 年,1 月   阅读总量:1621 已被赞:0


【多级评论的实现】

我这里的多见评论,我通过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,lftrghttree_id字段,这些字段是MPTT算法所使用的,一般不会用到!

【迁移数据库】

python manage.py makemigrations
python manage.py migrate

【前端页面显示】

blog/post_read.html里直接使用recursetree标签,就能将评论全部显示出来了

recursetree标签里,会添加两个上下文变量nodechildren

  • 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




登陆后方可评论