django树形结构之博客评论案例-优化篇mptt

小猫咪

前言说明

上一篇文章《django树形结构之博客评论案例-基础篇》 介绍了评论的基本实现,包含回复功能 , 但是美中不足的是页面展示无法实现树状层级化展示。

其实说不能实现,也不全对,因为Django默认提供了一个内置过滤器unordered_list ,官网说明参考 。但是 unordered_list 存在两个限制

1、需要单独定义一个递归行数,把数据库中的结果重新保存为嵌套结构,同时需要在view视图中先获取顶层记录

# views.py
def recurse_display(data):
    """递归展示"""
    display_list = []
    for item in data:
        display_list.append(item)
        children = item.children.all()
        if len(children) > 0:
            display_list.append(recurse_display(children))
    return display_list


def detail(request, id):
    post = Post.objects.get(pk=id)
    top_comoments = Comments.objects.filter(parent_comment=None)
    comoments = recurse_display(top_comments)
    return render(request, 'comment/detail.html', {'comoments': comoments, "post": post})

2、在template中使用 unordered_list 可以进行树状层级展示,但是无法添加样式

MPTT使用

1、安装

pip install django-mptt

2、配置

# settings.py
INSTALLED_APPS = [
    ... ...,
    'mptt',
]

3、模型定义

# models.py
from mptt.models import MPTTModel, TreeForeignKey
class CommentMPTT(MPTTModel):
    # 注意这里使用 TreeForeignKey
    post = models.TreeForeignKey(Post, on_delete=models.DO_NOTHING, verbose_name="评论的文章")
    ... ...
    # 建议默认取名 parent
    parent_comment = models.ForeignKey('self', null=True, on_delete=models.DO_NOTHING, verbose_name="回复的评论")
    
    class MPTTMeta:
        # 如果关联自身的属性不是 `parent` 则需要特殊指定
        parent_str = 'parent_comment'

3、视图函数

def detail(request, id):
    def detail(request, id):
    post = Post.objects.get(pk=id)
    comoments = Comments.objects.all()
    return render(request, 'comment/detail.html', {'comoments': comoments, "post": post})

4、template模板

<!-- 需要在页面最开始配置加载 mptt_tags 标签 -->
{% load mptt_tags %}

<!-- 在页面需要展示 评论列表的地方 -->
<!-- comment list -->
<div class="row">
    <h5>评论列表, 总 <span>{{  comments.count }}</span> 条评论</h5>
    {% recursetree comments %}
    {% with comment=node %}
    <div class="{% if comment.parent_comment %} offset-1 col-11 {% else %} col-12{% endif %}">
        <hr>
        <p>
            <strong style="color: orange;">
                {{ comment.comment_user }}
            </strong>
            {% if comment.parent_comment %}
            <strong style="color: orange;">
                => {{ comment.parent_comment.comment_user }}
            </strong>
            {% endif %}
        </p>
        <div>
            {{ comment.comment_body|safe }}
        </div>
        <div>
            <span style="color: gray;">{{ comment.comment_time|date:"Y-m-d H:i" }}</span>
            <button class="reply" username="{{ comment.comment_user }}" pk="{{ comment.pk }}">Reply</button>
        </div>

        {% if not comment.is_leaf_node %}
        <div class="children">
            {{ children }}
        </div>
        {% endif %}
    </div>
    {% endwith%}
    {% endrecursetree %}
</div>

然后进行评论回复评论测试 ,效果如下

django-blog-comment-03

这里发现,针对同一个顶级评论下的多次评论然后产生多级层次,如果回复很多,将会导致无限层级 在页面展示上也不美观

所以一般我们都是按照两级层级展示 ,所以这里需要对comment 视图函数做修改

# views.py 
# 这里只展示核心变动
if pid:
    ## 添加代码进行层级转化,大于2层的都转化为2层
    parent_comment = CommentMPTT.objects.get(id=pid)
    new_comment.parent_comment_id = parent_comment.get_root().id
    # new_comment.parent_comment_id = pid

然后进行评论回复评论测试 ,效果就按照如期的两级层级展示了

django-blog-comment-04

至此,大家是不是觉得完美了呢?

其实还是有个小问题的,不知道大家发现没有

李四回复张三的时候,消息显示@张三 xxxx 是没有问题,但是在消息头 谁回复谁 这里是不是都成了 回复 Colin, 也就是全部回复顶级父节点

扩展

两种解决办法

1、不展示消息头部的 谁回复谁 ,因为在回复消息的时候,已经 @ 回复的人了。

同时这里可以从页面设置不同颜色来体现,然后再后台也针对回复的人发送消息

2、如果非要展示,那就在模型中在添加一个字段属性 reply_to ,然后在 comment 视图函数中修改 reply_to的具体人

# views.py
# views.py 
# 这里只展示核心变动
if pid:
    ## 添加代码进行层级转化,大于2层的都转化为2层
    parent_comment = CommentMPTT.objects.get(id=pid)
    new_comment.parent_comment_id = parent_comment.get_root().id
    # 回复人
    new_comment.reply_to = parent_comment.comment_user
    # new_comment.parent_comment_id = pid

然后在template模型中修改

{% if comment.parent_comment %}
<strong style="color: orange;">
    => {{ comment.reply_to }}
</strong>
{% endif %}

最终的效果如下

image-20221014121513820


完美实现~ 项目源码详见
https://gitee.com/colin5063/django_learning_v2/tree/django_blog_comment_v2/

如果觉得文章对你有用,请不吝点赞和关注公众号搜索 全栈运维 或者 DailyJobOps

个人博客 http://blog.colinspace.com/

知乎平台 https://www.zhihu.com/people/colin-31-49

CSDN平台 https://blog.csdn.net/eagle5063

简书平台 https://www.jianshu.com/u/6d793fbacc88

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值