Django 评论楼创建

Django 评论楼创建

【零】最终效果预览

在这里插入图片描述

在这里插入图片描述

【一】介绍

(1)情况说明

  • 在Django模型层中有这么个字段
parent = models.ForeignKey(to='self', on_delete=models.CASCADE, verbose_name="父评论ID", null=True, blank=True)
  • 这个字段是一对多的外键字段
    • 其中to='self'说明是自关联
    • 当有子评论时,通过添加父评论的ID实现主评论和子评论的相关联
  • 那么就可以得到这么一个关系图

在这里插入图片描述

  • 这个是我们理想中应该存在的情况
    • 每一个评论都可以有子评论,且可以有多个子评论
    • 这就是数据结构中的森林,每一个评论楼都是一个N叉树
    • 每一个子评论都可以根据父评论ID获取父评论的所有信息
      • 包括父评论用户名等所有信息
  • 所以就存在这么一个问题
    • 如何将每一个子评论渲染到对应的评论楼中

(2)解决办法思路

  • 既然这是个森林那么就可以使用广度优先算法解决

    • 难度相对来说有点复杂
  • 有没有简单的办法呢

    • 只要是个树那么就很难不用到广度优先遍历
    • 所以就是破坏这个树
  • 这个是新的评论关系

    • 模型层部分代码

    • # 自动关联主评论,这个只是主评论楼ID
      parent = models.ForeignKey(to='self', on_delete=models.CASCADE, verbose_name="主评论楼ID", null=True, blank=True, related_name='children')
      # 将主评论ID和用户名分开保存
      parent_name = models.CharField(max_length=32, verbose_name='父评论名字', null=True, blank=True)
      
  • 这是新的评论楼关系图
    在这里插入图片描述

  • 说明

    • 每一个评论下都渲染这个评论下的所有子评论
    • 现在任然存在子评论的子评论
      • 不过子评论的id直接指向评论楼楼主的ID
    • 但是这样就少了被回复的那个人的用户名
      • 父评论ID智能找到楼主信息
    • 所以还有一个字段
      • 保存被回复的用户名称

【二】代码说明

(1)模型层代码说明

  • 主要说明一下parent字段的related_name

    • 这个属性定义了反向关系

    • 通过反向关系可以拿到所有的子评论

    • 但是还需要定义一个获得子评论的方法

    • def get_children(self):
          return self.children.all()
      
    • 这样就可以很轻松的拿到所有评论楼下的所有子评论信息

class Comment(BaseModel):
    content = models.CharField(max_length=255, verbose_name="评论内容")
    is_deleted = models.BooleanField(default=False, verbose_name="评论是否哦被删除")

    # 自动关联主评论,这个只是主评论楼ID
    parent = models.ForeignKey(to='self', on_delete=models.CASCADE, verbose_name="主评论楼ID", null=True, blank=True,
                           related_name='children')
    # 将主评论ID和用户名分开保存
    parent_name = models.CharField(max_length=32, verbose_name='父评论名字', null=True, blank=True)
    
    # 关联用户
    user = models.ForeignKey(to='user.UserInfo', on_delete=models.CASCADE, verbose_name="用户")
    # 关联文章
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE, verbose_name='文章')

    class Meta:
        db_table = 'comment'
        verbose_name_plural = '评论表'

    def get_children(self):
        return self.children.all()

(2)视图层代码说明

(2.1)展示评论楼说明
  • 这个很简单
    • 首先对过滤掉非本文章的评论
    • 然后遍历出所有评论楼
      • 就是父评论为空的评论
def article_detail(request, username, article_id):
    user_obj = UserInfo.objects.filter(username=username)
    if not user_obj:
        return render(request, 'error.html', locals())

    # 文章详情
    article_info_obj = Article.objects.filter(pk=article_id).first()

    # 文章评论
    all_comment_queryset = Comment.objects.filter(article=article_info_obj)
    comment_queryset = all_comment_queryset.filter(parent=None)

    return render(request, 'article_detail.html', locals())

(2.2)添加评论说明
  • 首先获取前端发送的所有信息,主要的是
    • 评论楼ID和父评论名字
    • 如果这个有值,那么就是子评论
    • 如果这个没有值,那么就是一个新的评论楼
  • 这里的创建新评论楼的好处
    • 不需要判断评论楼ID和父评论是否有值
    • 因为模型层是允许为空的
@login_required
def comment(request):
    if request.is_ajax():
        # 获取前端信息
        article_id = request.POST.get("article_id")
        parent_id = request.POST.get("parentId")
        content = request.POST.get("content")
        username = request.POST.get("username")
        # 评论不能为空判断
        if not all([article_id, content]):
            return json_response(code=2002, error='评论不能为空')
        # 创建评论
        Comment.objects.create(content=content, parent_id=parent_id, user=request.user, article_id=article_id,
                               parent_name=username)
        # 评论数增加
        article_obj = Article.objects.filter(pk=article_id).first()
        article_obj.comment_num += 1
        article_obj.save()
        return json_response()
    return json_response(code=2001, error='非ajax请求')

(3)模板层代码说明

(3.1)展示评论
  • 首先遍历所有的评论楼
    • 然后通过模型层的方法get_children()
    • 获得所有的子评论
      • 再次循环遍历渲染子评论信息即可
  • 需要注意的点是
    • 所有的子评论都要保存评论楼的楼主ID
    • 这样才是新的模型层关系
<li class="media" style="border: 1px solid #72CDFC; border-top-width: 2px; border-bottom: none;"
id="comment-media-list">
{% for comment_obj in comment_queryset %}
    {#评论头部#}
    <div class="media-heading" style="margin-bottom: 10px">
        <span>#{{ forloop.counter }}楼</span>
        <span>{{ comment_obj.create_time|date:"Y-m-d H:i" }}</span>
        <span>{{ comment_obj.user.username }}</span>
        <span><a href="javascript:;" class="pull-right comment-replay"
                 username="{{ comment_obj.user.username }}"
                 comment-id="{{ comment_obj.pk }}">回复@{{ comment_obj.user.username }}</a></span>
    </div>
    {#评论内容#}
    <div class="media-body">
        {{ comment_obj.content }}
        {% if comment_obj.get_children %}
            <a class="pull-right" role="button" data-toggle="collapse"
               href="#collapseExample{{ comment_obj.pk }}"
               aria-expanded="false" aria-controls="collapseExample">
                查看更多
            </a>
            <div class="collapse" id="collapseExample{{ comment_obj.pk }}">
                <div class="well">
                    {% for children in comment_obj.get_children %}
                        <p style="margin-bottom: 5px">
                            {{ children.user.username }}@{{ children.parent_name }}
                            <span><a href="javascript:;" class="pull-right comment-replay"
                                     username="{{ children.user.username }}"
                                     comment-id="{{ comment_obj.pk }}">回复@{{ children.user.username }}</a></span>
                        </p>
                        <div>
                            {{ children.content }}
                        </div>
                        <hr style="border: 1px solid #72CDFC; width: 100%; margin-bottom: 0;">
                    {% endfor %}
                </div>
            </div>
        {% endif %}
    </div>
    <hr style="border: 1px solid #72CDFC; width: 100%; margin-bottom: 0;">
{% endfor %}
</li>
(3.2)添加评论Ajax
  • 回复评论的处理
    • 获取被回复对象的用户名和评论楼的ID
    • 添加指定格式
    • 渲染到评论框中,并聚焦focus()
  • 提交评论给后端Ajax
    • 添加到评论框中的内容并不是全都要保存在数据库中比如@admin
    • 所以先对这部分进行切分处理
    • 然后传递信息给后端对应的路由
  • 从后端拿到返回信息
    • 错误的信息,进行指定位置的渲染
    • 正确的信息,先显示在底部,提供一个刷新按钮
      • 点击刷新即可完成评论的添加
<script>
    $(document).ready(function () {
        // 父评论默认是空的
        let parentId = null
        // 回复平理论处理
        $(".comment-replay").click(function () {
            let commentUsername = $(this).attr('username')
            parentId = $(this).attr('comment-id')
            // 拼接字符到评论框,并且聚焦
            $("#comment-text").val("@" + commentUsername + '\n').focus()
        })

        $("#comment-submit").click(function (e) {
            e.preventDefault()
            // 获取评论类容
            let content = $("#comment-text").val()
            // 对次评论进行头部处理
            if (parentId) {
                let indexNum = content.indexOf('\n') + 1
                // 使用trim移除前后的空白名
                // 保留回复人的信息
                var username = content.slice(1, indexNum).trim();
                // 评论内瓤
                content = content.slice(indexNum).trim();
            }
            // 发送ajax请求
            $.ajax({
                url: "{% url 'comment' %}",
                type: 'post',
                data: {
                    "article_id": "{{ article_info_obj.pk }}",
                    "content": content,
                    "csrfmiddlewaretoken": "{{ csrf_token }}",
                    "parentId": parentId,
                    "username": username,
                },
                success: function (response) {
                    if (response.code === 2000) {
                        // 清空评论框中的内容
                        $("#comment-text").val('')
                        // 评论者的名字
                        let userName = '{{ request.user.username }}'
                        // 使用模板语法渲染信息
                        let newComment = `
                    <div class="media-heading" style="margin-bottom: 10px">
                        <span>${userName}</span>&nbsp;&nbsp;&nbsp;
                <span><a onclick="window.location.reload()" style="color: blue">刷新</a></span>
                    </div>
                    <div class="media-body">
                        ${content}
                    </div>
                    <hr style="border: 1px solid #72cdfc; width: 100%; margin-bottom: 0;">
`
                        // 添加到末尾
                        $("#comment-media-list").append(newComment)

                    } else {
                        $("#comment-error").text(response.error)
                    }
                    // 请求结束以后需要重置
                    parentId = null
                }
            })
        })
    })
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/495855.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis入门到实战-第十九弹

Redis实战热身Count-min-sketch篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、…

验证码demo(简单实现)

前言 我们注意到我们登录网站的时候经常会用到网络验证码,今天我们就简单实现一个验证码的前后端交互问题,做一个小demo 准备 我们这里并不需要依靠原生的java来实现,而是只需要引入一个maven依赖,使用现成的封装好的即可,这是我使用的是hutool工具包 网址:Hutool&#x1f36c;…

MySQL 8:GROUP BY 问题解决 —— 怎么关闭ONLY_FULL_GROUP_BY (详细教程)

在使用 GROUP BY 时&#xff0c;我们可能会遇到以下报错&#xff1a; Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column …… 这是因为我们在select语句中所查询的列并不被group by后面接的列所包含。 对于GROUP BY聚合操作&#xf…

油缸位置传感器871D-DW2NP524-N4

概述 油缸位置传感器是一种使用电感原理来检测物体接近的开关装置。它通过感应物体的电磁场来判断物体的位置&#xff0c;并将信号转化为电信号输出。当物体靠近或远离电感式接近开关时&#xff0c;物体的电磁场会改变&#xff0c;从而使接近开关产生不同的信号输出。电感式接…

Go —— defer

defer defer 语句用于延迟函数的调用&#xff0c;常用于关闭文件描述符、释放锁等资源释放场景。但 defer 关键字只能作用于函数或函数调用。 defer func(){ // 函数fmt.Print("Hello&#xff0c;World!") }()defer fmt.Print("Hello&#xff0c;World!&…

如何在CentOS安装可视化Docker容器管理工具Portainer并无公网IP远程管理

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

智慧公厕,为智慧城市建设注入了新的活力

随着智慧城市的快速发展&#xff0c;公共厕所不再是简单的功能设施&#xff0c;而是成为了提升城市形象、改善民生服务的重要一环。智慧公厕作为新形态的公共厕所&#xff0c;通过精准监测公厕内部的人体活动状态、人体存在状态、空气质量情况、环境变化情况、设施设备运行状态…

Occupancy 后处理

文章目录 bev坐标与自车坐标转换如何创建旋转矩阵 (R_veh) 偏航3D Voxel -> 2D Grid 在进行占据空间&#xff08;occupancy&#xff09;后处理时&#xff0c;需要将不同感知模块的输出进行综合融合&#xff0c;以实现更精确的空间占据和环境感知。以下是针对您提到的几个方面…

Java代码基础算法练习-求一个三位数的各位数字之和-2024.03.27

任务描述&#xff1a; 输入一个正整数n&#xff08;取值范围&#xff1a;100<n<1000&#xff09;&#xff0c;然后输出每位数字之和 任务要求&#xff1a; 代码示例&#xff1a; package M0317_0331;import java.util.Scanner;public class m240327 {public static voi…

LangChain入门:2.OpenAPI调用ChatGPT模型

引言 在本文中&#xff0c;我们将带您深入探索如何通过OpenAPI与ChatGPT模型进行高效交互&#xff0c;实现智能文本问答功能。通过LangChain库的实践&#xff0c;您将学习构建一个能够与用户进行自然语言对话的系统的关键步骤。 准备步骤 在动手编码之前&#xff0c;请确保您…

Linux之进程控制进程终止进程等待进程的程序替换替换函数实现简易shell

文章目录 一、进程创建1.1 fork的使用 二、进程终止2.1 终止是在做什么&#xff1f;2.2 终止的3种情况&&退出码的理解2.3 进程常见退出方法 三、进程等待3.1 为什么要进行进程等待&#xff1f;3.2 取子进程退出信息status3.3 宏WIFEXITED和WEXITSTATUS&#xff08;获取…

从零开始的软件开发实战:互联网医院APP搭建详解

今天&#xff0c;笔者将以“从零开始的软件开发实战&#xff1a;互联网医院APP搭建详解”为主题&#xff0c;深入探讨互联网医院APP的开发过程和关键技术。 第一步&#xff1a;需求分析和规划 互联网医院APP的主要功能包括在线挂号、医生预约、医疗咨询、健康档案管理等。我们…

2024河北煤炭装备展览会|河北采煤装备展会|河北煤博会

2024中国&#xff08;石家庄&#xff09;国际煤炭装备及矿山设备博览会 时间&#xff1a;2024年7月4-6日 地点&#xff1a;石家庄国际会展中心.正定在快速发展的科技时代&#xff0c;能源行业始终是国家发展的重要支柱。作为传统的能源巨头&#xff0c;煤炭产业在面临转型升…

jdk8中的Arrays.sort

jdk8中Arrays.sort 这里可以看到根据传入数组类型的不同&#xff0c;排序的算法是由区别的。 拆分解析 我们在平时引用的时候&#xff0c;一般只会传入一个数组&#xff0c;但是真正调用的时候&#xff0c;参数会进行补全。 public static void sort(int[] a) {DualPivotQui…

获奖喜讯 | 思迈特软件蝉联双奖,品牌及产品实力再获认可

近期&#xff0c;思迈特软件又传来获奖捷报&#xff0c;凭借出色的产品力及品牌实力&#xff0c;思迈特软件Smartbi一站式大数据分析平台荣登2023ToB头条影响力价值榜“创新力产品TOP50”榜单&#xff0c;又获广东省云计算应用协会“2023年度大数据创新企业奖”。 荣登“ToB行业…

贪心算法--最大数

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 本题链接https://leetcode.cn/problems/largest-number/description/ class Solution { public:bool static compare(int a, int b){return (to_string(a) to_string(b)) > (to_string(b) to_string(a));}bool operato…

爱思助手验机不靠谱?

1.骗子只能骗的一种人就是有点懂 因为完全不懂的不会感兴趣 骗不到 太懂的人 基本属于猴精的人 你骗不到 2. 3.基本做的是翻新机 维修过的 4。转载 爱思助手验机不靠谱&#xff1f;“报告全绿”已成奸商的阴谋 - 知乎

Windows无法安装torch==1.4.0

在conda中&#xff0c;每创建一个虚拟环境&#xff0c;就要重新配置其中的pytorch 这次我创建的虚拟环境需要torch1.4.0的版本。 torch网址&#xff1a;https://pytorch.org/get-started/previous-versions/ 解决办法 按以下代码进行安装&#xff1a; pip install torch0.4.0…

短视频账号矩阵系统/开发 -- -- -- 蒙太奇算法上线

短视频账号矩阵系统&#xff0c;短视频矩阵系统开发3年技术之路&#xff0c;目前已经在技术竞品出沉淀出来&#xff0c;近期技术迭代的新的功能同步喽&#xff1a; php7.4版本&#xff0c;自研框架&#xff0c;有开发文档&#xff0c;类laravel框架 近期剪辑迭代的技术算法&am…

【Pytorch入门】小土堆PyTorch入门教程完整学习笔记(详细笔记并附练习代码 ipynb文件)

小土堆PyTorch入门教程笔记 最近在观看PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆】顺便做点笔记&#xff0c;方便回看&#xff0c;同时也希望记录的笔记能够帮助到更多在入门的小伙伴~ 【注】仅记录个人觉得重要的知识&#xff0c…