【Django2.0学习笔记】26.回复功能设计和树结构

26、回复功能设计和树结构

本节课想要实现如下效果:
在这里插入图片描述

1、如何设计回复功能

  • 评论可被回复
  • 回复可被回复
    在这里插入图片描述

在comment/models.py中,如果新添加一个回复的类Reply,外键关联到Comment这个类,这样可以实现“评论可被回复”,但“回复可被回复”这个功能,又得新建一个类,然后外键关联到Reply,这样关联下去,显然是不可行的。

实际上,回复也是一种评论的行为,说明回复的本质也是评论,既然这样的话,那我们回复功能可不可以在Comment这个模型里面实现呢?
'content_object’这个类型可以指向任意的对象,可以指向评论的博客,那么也可以指向评论这个模型,评论这个评论,当然这种做法是可以的,不过比较麻烦,就单单我们一条评论要找下面多条回复的时候,就要反复的递归才能得到结果,这样就不是很合理。

那么我们这里怎么去实现它呢?这里就涉及到一种叫做树结构的东西。
我们可以新建一个字段,记录评论的上一级相关信息。这样就可以只用一个字段就可以关联到上一级
在这里插入图片描述
同步数据库,重启服务,刷新后台页面
在这里插入图片描述
这里parent_id选择回复的是哪一条评论(如果是一条评论的话, 就选0)。所以如果我们想要回复某一条评论的话,我们需要知道它具体的主键值是什么。

我们先让每条评论显示出来自己的主键值,需要修改comment/admin.py,加一个“id”字段:
在这里插入图片描述
在这里插入图片描述
添加一条评论,选择parent_id为2(意思就是这条评论是回复的上面id为2的那条评论,parent_id已经记录了它所回复的那条评论的主键信息)
在这里插入图片描述
这里有点麻烦,我们每次都要查看记住回复的评论的id值。
我们可以用一个外键,指向自己self,null=True表示允许它为空(因为如果这条评论是顶级评论,而不是回复的话,这个字段值就允许为空)
在这里插入图片描述
刷新,就可以看到这里可以直接选择回复哪条评论了,但是这里还不是很清楚,我们还需要再改一个地方
在这里插入图片描述
新加一个__str__方法:
在这里插入图片描述

【补充】
在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法;
当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据;
__str__方法需要返回一个字符串,当做这个对象的描写

在这里插入图片描述
可以看到,这里就可以选择具体评论内容了

这里只是初步的实验,要用到前端页面,我们还需要进一步优化
修改models.py如下:
新增reply_to = models.ForeignKey(User, null=True, on_delete=models.DO_NOTHING),上面也有一条ForeignKey指向User会报错显示有冲突。原因是:外键关联是双向的。我们可以通过评论Comment找到对应的user,在用户User那里也可以反向找到对应的那些评论Comment。如果我们第二条reply_to不写,我们是怎么样通过user得到对应的有哪些评论呢?这里我们可以用shell演示下在这里插入图片描述
在这里插入图片描述
这里user有一个comment_set,通过comment_set.all()就可以反向得到相关评论的集合。这就是通过user反向得到评论Comment。这里默认命名就是模型的小写comment加一个_set。

而如果我们加上reply_to这一行代码的话,就有两个外键偶读指向User,那么就不知道应该是哪一条与Comment对应了。那么这里我们就可以设置一个属性related_name
在这里插入图片描述
可以看到user里面就有comments和replies(因为是刚刚创建的,所以没有数据)。这样,通过写related_name,就能解决外键冲突问题,明确对应的关系
在这里插入图片描述
另外,我们还要加一个字段,我想要获取一条评论下面的所有回复,那么就需要记录每一条回复是基于哪一条评论开始的,也就是该条回复的最顶级是哪一条评论。这样我们就可以直接通过一个筛选条件filter直接得到这条评论下面相关的回复。
修改models.py如下:
在这里插入图片描述
更改模型之后,接下来一步,我们要看对应的处理方法要不要改动。
像blog/views.py里面的blog_detail,打开某一篇具体博客的时候,里面的comments,要稍作修改
在这里插入图片描述

那么具体的评论回复要怎么显示呢?我们可以在模板页面处理
blog_detail.html
在这里插入图片描述
在后台页面添加一条回复
在这里插入图片描述
然后刷新前端页面,可以看到顶级评论后面跟着刚刚添加的那条回复了
在这里插入图片描述
我们先来调整一下前端页面,
修改blog_detail.html如下:
在这里插入图片描述

修改blog/static/blog/blog.css如下:
在这里插入图片描述
刷新页面
在这里插入图片描述

接下来我们加一个回复的按钮
回到comment/forms.py,再多添加一个提交的字段 reply_comment_id
在这里插入图片描述
另外,这个字段有个初始化的事情要做,在blog/views.py里面的blog_detail,reply_comment_id一般默认为0 的话就是顶级评论:
在这里插入图片描述
在这里插入图片描述
可以看到reply_comment_id这个id标签值value为0 ,说明默认是顶级评论,如果是回复评论,那么我们将是这个标签值改为对应回复的评论的主键值就可以

再修改blog_detail.html,在评论列表里添加“回复”的链接 a标签
在这里插入图片描述

另外在下面拓展方法的位置,我们再多写一个function如下:
在这里插入图片描述
那么我们要怎么调用这个方法呢?在上面的a标签那里
在这里插入图片描述
然后我们在页面,点击某条评论下面的“回复”按钮,那么value值就会变成这条评论对应的主键值
在这里插入图片描述

接下来,我们想要点击回复之后,让那条评论显示在评论框上面
可以通过ajax代码实现
修改blog_detail.html如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
刷新页面,点击回复,可以看到这个评论就会显示在评论框上方
在这里插入图片描述
然后我们写入回复的内容,点击“评论”,我们的数据就会提交到表单的CommentForm的处理方法views,views接收到数据 进行判断,那我们先进行数据验证,在forms里面写一个clean方法
修改forms.py如下:
在这里插入图片描述
这里我们验证处理完成之后,我们怎么去更新数据?现在我们要加一下回复的数据进去,我们就判断是不是回复。修改comment/views.py如下:
在这里插入图片描述
这样,我们后端处理逻辑就完成了,我们刷新页面
在这里插入图片描述
完善:如果是评论,我们就写到第一条,如果是回复,我们就写到对应的位置下面。需要打开前端代码进行修改。

首先在comment/views.py返回的数据里面多加一个root_pk字段:
在这里插入图片描述

前端代码里,插入数据部分,需要分两种情况:一种是评论、一种是回复。以下代码做一个判断

修改blog_detail.html如下(先给一些内容加一些span标签):
在这里插入图片描述
在这里插入图片描述
刷新页面
在这里插入图片描述
这样,我们就完成了回复评论的功能

还剩一些细节的处理:
原本的页面:
在这里插入图片描述
提交回复后,清理掉评论框上方显示的内容。这里我们只需要将它设置隐藏就可以,修改blog_detail.html如下:
在这里插入图片描述
刷新页面
在这里插入图片描述

还有一个细节,评论列表的排序
在这里插入图片描述

回复评论我们改为正序,让评论由小到大的日期排序,修改models.py如下。但是回复和评论的排序是反过来的,评论是倒序的(最新评论在最上面),回复是正序的(第一条回复在最上面)。我们有两个地方需要处理,另外一个地方是blog/views.py,让它倒序显示
在这里插入图片描述
在这里插入图片描述
刷新页面:
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值