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="评论是否哦被删除")# 自动关联主评论,这个只是主评论楼IDparent = 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 += 1article_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>

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

linux中查看内存占用空间

文章目录 linux中查看内存占用空间 linux中查看内存占用空间 使用 df -h 查看磁盘空间 使用 du -sh * 查看每个目录的大小 注意这里是当前目录下的文件大小&#xff0c;查看系统的可以回到根目录 经过查看没有发现任何大的文件夹。 继续下面的步骤 如果您的Linux磁盘已满&a…

快速上手Spring Cloud 十五:与人工智能的智慧交融

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

【scala】使用gradle和scala构建springboot程序

零、版本说明: springboot: 2.7.18 使用log4j2&#xff0c;不使用springboot自带的logback scala版本&#xff1a;2.11 jackson版本&#xff1a;2.16.0 一、依赖&#xff1a; buildscript {dependencies {// using spring-boot-maven-plugin as package toolclasspath("…

FIBEX文件详细解析

文件概况 FIBEX文件是flexray的数据库文件&#xff0c;相当于CAN的DBC。 首先得了解这种文件的架构&#xff0c;就像下图那样&#xff0c;所以本文也是按照这个架构来进行展开讲解。project和PROCESSING-INFORMATION都是次要的&#xff0c;最重要的是ELEMENTS里面的5个元素。…

【Redis教程0x08】详解Redis过期删除策略内存淘汰策略

引言 Redis的过期删除策略和内存淘汰策略是经常被问道的问题&#xff0c;这两个机制都是做删除操作&#xff0c;但是触发的条件和使用的策略是不同的。今天就来深入理解一下这两个策略。 过期删除策略 Redis 是可以对 key 设置过期时间的&#xff0c;因此需要有相应的机制将…

SPDZ基础使用手册(深度学习视角)

基本类型 深度学习中最常使用的便是秘密定点数sfix&#xff0c;有关定点数的高级运算协议请参阅Paper: Secure Computation With Fixed-Point Numbers. 容器类型 SPDZ的深度学习框架主要基于TensorFlow实现&#xff0c;其中使用的容器是张量Tensor&#xff0c;在库中的定义如下…

[LeetCode]516. 最长回文子序列[记忆化搜索解法详解]

最长回文子序列 LeetCode 原题链接 题目 给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a…

java回溯算法笔记

回溯算法综述 回溯用于解决你层for循环嵌套问题&#xff0c;且不剪枝的回溯完全等于暴力搜索。 回溯算法模板https://blog.csdn.net/m0_73065928/article/details/137062099?spm1001.2014.3001.5501 组合问题 不能重复使用的组合问题&#xff08;startindex i1&#xff09…

centos7.9安装mysql

1. 概述 官网&#xff1a;https://www.mysql.com/ MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Management S…

Kubernetes Gateway API 介绍

Kubernetes Gateway API 诞生背景 在 kubernetes 中&#xff0c;流量的治理主要分为两个部分&#xff1a; 南北向流量东西向流量 南北向流量&#xff08;NORTH-SOUTH traffic&#xff09; 在计算机网络中&#xff0c;南北向流量通常指数据流量从一个**内部网络&#xff08;…

鸿蒙--DevEco Studio安装步骤及配置

1.华为开发者联盟文档网站&#xff1a;文档中心 2.打开网页后&#xff0c;找到工具准备 (1). (2). (3). (4). (5).压缩包下载完成后解压 3.双击打开应用程序&#xff0c;进行如下操作&#xff1a; 以上步骤完成后&#xff0c;桌面上显示应用&#xff0c;双击打开&#xff1a;…

STM32G071 从 standby 模式退出后的 SRAM 数据保留

1.问题的描述 某客户使用 STM32G071 芯片从 standby 模式下唤醒&#xff0c;想要 SRAM 的数据在退出 standby模式后得以保持。根据手册的描述&#xff0c;配置了相应的比特位&#xff0c;但是发现数据仍然保持不了。 2.问题的复现 根据客户的描述&#xff0c;以及 STM32G071…

Excel:使用VLOOKUP函数,抓取指定数据,后一个列

Excel:使用VLOOKUP函数&#xff0c;抓取指定数据&#xff0c;后一个列 我们有这样一个数据源 要是实现这个页面的赋值 就是对应关系映射 使用 VLOOKUP(A2,Sheet2!$A$2:$B$9,2,FALSE)第一个参数是需要匹配的单元格。 第二个参数是数据源&#xff0c;我这里数据源用的是shee…

基于微信小程序的民宿短租系统设计与实现(论文+源码)_kaic

摘 要 随着社会的发展&#xff0c;出差、旅游成为常态&#xff0c;也就造成民宿短租市场的兴起。人们新到陌生的环境里找民宿一般都是通过中介。中介虽然可以快速找到合适的民宿但会收取大量的中介费用&#xff0c;这对刚到新环境里的人们来说是一笔大的资金支出。也有一些人通…

CMOS逻辑门电路

按照制造门电路的三极管不同&#xff0c;分为MOS型、双极性和混合型。MOS型集成逻辑门有CMOS、NMOS、PMOS&#xff1b;双极型逻辑门有TTL&#xff1b;混合型有BiCMOS。 CMOS门电路是目前使用最为广泛、占主导地位的集成电路。早期CMOS电路速度慢、功耗低&#xff0c;后来随着制…

小程序利用WebService跟asp.net交互过程发现的问题并处理

最近在研究一个项目&#xff0c;用到asp.net跟小程序交互&#xff0c;简单的说就是小程序端利用wx.request发起请求。获取asp.net 响应回来的数据。但经常会报错。点击下图的测试按钮 出现如下错误&#xff1a; 百思不得其解&#xff0c;试了若干方法&#xff0c;都不行。 因为…

Golang-Gin光速入门

安装 go get -u github.com/gin-gonic/gin初始化项目并启动服务 go mod init gin-project package mainimport "github.com/gin-gonic/gin"func main() {r : gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message"…

成都市酷客焕学新媒体科技有限公司:实现品牌的更大价值!

成都市酷客焕学新媒体科技有限公司专注于短视频营销&#xff0c;深知短视频在社交媒体中的巨大影响力。该公司巧妙地将品牌信息融入富有创意和趣味性的内容中&#xff0c;使观众在轻松愉悦的氛围中接受并传播这些信息。凭借独特的创意和精准的营销策略&#xff0c;成都市酷客焕…

常用植被物候提取方法 (TIMESATE/R语言/Python)-3.0

文章内容仅用于自己知识学习和分享&#xff0c;如有侵权&#xff0c;还请联系并删除 &#xff1a;&#xff09; 常用植被物候提取方法 (TIMESATE/R语言/Python)-1.0见 link常用植被物候提取方法 (TIMESATE/R语言/Python)-2.0见 link 这里主要介绍一下自己读到的论文&#xff…

element-ui 自定义点击图标/文本/按钮触发el-date-picker时间组件,不使用插槽

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1. 图片预览 2.上代码 2.1html <el-button class"hide_input" size"small"><svg t"1711608996149" class"icon" viewBox"0 0 1024 1024" version"1.1"…