您现在的位置是:网站首页>文章详情文章详情

Python多级评论系统的设计与实战

inlike2019-06-27 原创文章 浏览(1980) 评论(0) 喜欢(36)

简介多级评论系统的关键在评论表的设计、核心在如何按序取出对应的评论数据;在博客www.likeinlove.com 的开发中就遇到关于多级评论系统的处理,评论的顺序获取是使用Python的递归函数来实现。

多级评论系统的关键在评论表的设计、核心在如何按序取出对应的评论数据;在博客www.likeinlove.com 的开发中就遇到关于多级评论系统的处理,评论的顺序获取是使用Python的递归函数来实现。

image.png

首先是表的设计,分为一级评论的表和其余级评论的表,一级评论关联文章、其余级别的评论表关联自身或者关联一级评论,那么要实现两个关联就需要增加一个type字段,用来标示关联的是一级评论或者是关联评论的评论,两张表结构如下:

class Comment(models.Model):
    """一级评论类"""
    topic_id = models.IntegerField(null=True, blank=True)  # 文章id
    content = models.TextField(verbose_name='评论')  # 内容
    type = models.IntegerField(default=1, verbose_name='')  # 1-文章, 2-公告, 3-留言
    from_uid = models.ForeignKey(to='User', to_field='id',
                                 on_delete=models.CASCADE)  # 评论用户id
    notice = models.BooleanField(default=False, verbose_name='回复通知')
    is_top = models.BooleanField(default=False, verbose_name='置顶')  # 是否置顶
    is_hot = models.BooleanField(default=False, verbose_name='热评')  # 是否为热评
    like_num = models.IntegerField(default=0, verbose_name='点赞')  # 喜欢数
    reply_num = models.IntegerField(default=0, verbose_name='回复数')  # 回复数
    iddelete = models.BooleanField(default=False, verbose_name='删除')
    create_time = models.DateTimeField(auto_now_add=True,
                                       verbose_name='时间')  # 插入时间

    def __getattribute__(self, item):
        if item == 'content':
            iddelete = self.__dict__.get('iddelete')
            if iddelete:
                return '该评论已被删除'
            else:
                return self.__dict__.get('content')
        else:
            return object.__getattribute__(self, item)

    def getcomment(self):
        return {'comment': self.content, 'like_num': self.like_num
            , 'create_time': self.create_time.strftime(
                "%Y-%m-%d %H:%M:%S"), 'commentid': self.id, 'type': self.type,
                'headportrait': self.from_uid.headportrait.url,
                'form_name': self.from_uid.name}

    class Meta:
        verbose_name = "评论列表"
        verbose_name_plural = "评论管理"

    def __str__(self):
        return self.content


class Reply(models.Model):
    """多级评论类"""
    comment_id = models.IntegerField(verbose_name='关联被评论的评论id')  # 一级或者二级
    from_uid = models.ForeignKey(to='User', to_field='id', related_name='fid',
                                 on_delete=models.CASCADE,
                                 verbose_name='评论对象id')
    to_uid = models.ForeignKey(to='User', to_field='id', related_name='tid',
                               on_delete=models.CASCADE,
                               verbose_name='被评论对象id')  # 评论用户id
    commen_type = models.IntegerField(default=4,
                                      verbose_name='分类')  # 4评论一级评论, 5评论二级
    notice = models.BooleanField(default=False, verbose_name='通知')
    content = models.TextField()  # 正文
    like_num = models.IntegerField(default=0, verbose_name='喜欢')  # 喜欢数
    reply_num = models.IntegerField(default=0, verbose_name='回复')  # 回复数
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='时间')
    iddelete = models.BooleanField(default=False, verbose_name='删除')

    def __getattribute__(self, item):
        if item == 'content':
            iddelete = self.__dict__.get('iddelete')
            if iddelete:
                return '该评论已被删除'
            else:
                return self.__dict__.get('content')
        else:
            return object.__getattribute__(self, item)

    def getcomment(self):
        return {'type': self.commen_type, 'form_name': self.from_uid.name,
                'to_name': self.to_uid.name,
                'commentid': self.id,
                'comment': self.content,
                'tdatetime': self.create_time.strftime(
                    "%Y-%m-%d %H:%M:%S"), 'like_num': self.like_num,
                'headportrait': self.from_uid.headportrait.url,
                'to_id': self.comment_id}

    class Meta:
        verbose_name = "用户评论"
        verbose_name_plural = "评论管理"
        ordering = ['create_time']

    def __str__(self):
        return self.content

两张表中都有用于标示的type字段,Comment表中的type用来标示是关联文章还是关联公告,Reply多级评论表中的type用来标示多级评论关联一级评论,还是关联一级评论的评论;

    def __getattribute__(self, item):
        if item == 'content':
            iddelete = self.__dict__.get('iddelete')
            if iddelete:
                return '该评论已被删除'
            else:
                return self.__dict__.get('content')
        else:
            return object.__getattribute__(self, item)

    def getcomment(self):
        return {'comment'self.content, 'like_num'self.like_num
            , 'create_time'self.create_time.strftime(
                "%Y-%m-%d %H:%M:%S"), 'commentid'self.id, 'type'self.type,
                'headportrait'self.from_uid.headportrait.url,
                'form_name'self.from_uid.name}

__getattribute__的作用是用于内容拦截,当删除字段iddelete(id是失误本应写is的)为True的话返回评论内容“该评论已被删除”,反之返回正常的评论;getcomment的方法是返回评论的dict数据,不需要在view函数中组织评论的数据结构。

上面说完了评论的数据结构,下面来说如何根据一篇文章id或者公告id快速读取出相关的评论内容,并且保证输出的结果是按照评论顺序的。

image.png

(一级评论后台截图)

准确的需求是:一级评论按照一定规则排序(如热度、点赞、热评),但是一级评论下的其他评论,应该按照顺序排在对应的一级评论下面,保持队列完整性。

当初在解决这个问题的时候花了好几天的时间,最后用递归函数的方式来递归遍历出一级评论下的其他级别评论,该方式没有在大量数据的情况下验证,个人博客数据量最多几千上万,所以使用递归遍历对性能的影响较小,如果是大型的应用场景中,是否该考虑使用mongodb存储json格式。

    def forcomment(n_comment: list, items):
    """
    递归查询多级评论
    :param n_comment:
    :param items:
    :return:
    """

    for n in n_comment:
        n_comment = Reply.objects.filter(
            Q(commen_type=5) & Q(comment_id=n.id)).order_by(
            '-create_time')
        items.append(n)
        if len(n_comment) > 0:
            forcomment(n_comment, items)
    return items

该方法用于递归查询一级评论下的多级评论,传入的是某个文章下所有的一级评论列表,传入该函数后将会返回包含一级评论的所有多级评论列表:如n_comment = ["一级评论1","一级评论2","一级评论3","一级评论4","一级评论5"],那么它最后返回的结果是:["一级评论1","多级评论1","多级评论1","多级评论1",······,"一级评论2","多级评论1","多级评论1","多级评论1",······,"一级评论3","多级评论1","多级评论1","多级评论1",······,"一级评论4","多级评论1","多级评论1","多级评论1",······,"一级评论5",·······]这样的数据是可以满足的需求的。

其实还可以优化一下,让最后数据成为这种格式:

[["一级评论1","多级评论1","多级评论1","多级评论1",······],

["一级评论2","多级评论1","多级评论1","多级评论1",······],

["一级评论3","多级评论1","多级评论1","多级评论1",······],

["一级评论4","多级评论1","多级评论1","多级评论1",······],

["一级评论5",·······]

要变成这种格式也很简单,不在累述了,欢迎关注个人微信公众号:Python之战

个人博客:www.likeinlove.com

image.png

(多级评论后台截图)

很赞哦! ( 36)
    《Python实战进阶》
    None
    None
    夏至已深

站点信息

  • 建站时间:2019-5-24
  • 网站程序:like in love
  • 主题模板《今夕何夕》
  • 文章统计:104条
  • 文章评论:***条
  • 微信公众号:扫描二维码,关注我们
  • 个人微信公众号