当前位置: 首页 > news >正文

BBS项目day04 文章详情页、点赞点菜、评论功能(根评论和子评论)、评论分页之刷新评论页面

一、路由

from django.contrib import admin
from django.urls import path, re_path
from app01 import views
from django.views.static import serve
from django.conf import settingsurlpatterns = [path('admin/', admin.site.urls),# 注册path('register/', views.register),# 登录path('login/', views.login),# 验证码path('get_code/', views.get_code),# 首页路由path('home/', views.home),# 退出系统path('logout/', views.logout),# 修改密码path('set_password/', views.set_password),# 放开media文件夹re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),# 点赞点彩path('up_and_down/', views.up_and_down),# 评论功能path('comment/', views.comment),# re_path('(?P<username>\w+)/category/(\d+)', views.site),# re_path('(?P<username>\w+)/tag/(\d+)', views.site),# re_path('(?P<username>\w+)/archive/(\w+)', views.site),# 优化以上三个路由re_path('(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)', views.site),# 文章详情页re_path('(?P<username>\w+)/(?P<article_id>\d+)', views.article_detail),# 放开media文件夹  \w+ 匹配数字字母下划线re_path('(?P<username>\w+)', views.site),
]

二、文章详情页

1.前端

{% extends 'home.html' %}{% block css %}<style>.s1 {margin-right: 10px;color: #999;}.content {font-size: 18px;color: #444;}#div_digg {float: right;margin-bottom: 10px;margin-right: 30px;font-size: 12px;width: 128px;text-align: center;margin-top: 10px;}.diggit {float: left;width: 46px;height: 52px;background: url(/static/img/upup.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.buryit {float: right;margin-left: 20px;width: 46px;height: 52px;background: url(/static/img/downdown.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.clear {clear: both;}.diggword {margin-top: 5px;margin-left: 0;font-size: 12px;color: #808080;}.clearfix:focus {content: '';display: block;clear: both;}</style>
{% endblock %}{% block content %}<div class="col-md-3"><div class="panel panel-info"><div class="panel-heading">文章分类</div><div class="panel-body">{% for category in category_list %}<!-- 如果后台用的是values --><p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }} ({{ category.1 }})</a></p><!-- 如果后台用的是values -->{#                    <p><a href="/{{ username }}/category/{{ category.pk }}">{{ category.name }} ({{ category.count_article_num }})</a></p>#}{% endfor %}</div></div><div class="panel panel-success"><div class="panel-heading">文章标签</div><div class="panel-body">{% for tag in tag_list %}<p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }} ({{ tag.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-danger"><div class="panel-heading">日期归档</div><div class="panel-body">{% for date in date_list %}{#  <p><a href="">{{ date.0 }} ({{ date.1 }})</a></p> #}<p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }}({{ date.count_article_nums }})</a></p>{% endfor %}</div></div></div><div class="col-md-9"><h3 style="color: #399ab2;">{{ article_detail.title }}</h3><div class="content">{{ article_detail.content|safe }}</div></div>{% endblock %}{% block js %}<script>// 11647089,'Digg'分别表示文章id和标志flag// 思路1:{% comment %}function votePost(id, flag) {is_up = flag === 'Digg' ? 0 : 1;}{% endcomment %}// 思路2:$(".active").click(function () {let is_up = $(this).hasClass('diggit');// 文章idvar article_id = '{{ article_detail.pk }}';var _this = $(this);// 发起Ajax请求$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up, article_id: article_id, csrfmiddlewaretoken: '{{ csrf_token }}'},success: function () {// 将标签放入文本,要么是text,要么是htmlif (res === 200) {$("#digg_tips").text(res.msg);// 如果是点赞就让点赞数加1,如果是点踩就让点踩数加1// 注意:在text()中加数据就是赋值,空就是获取值let old_num = _this.children().text();// 此时的 old_num 是string类型,需要转类型{#_this.children().text(parseInt(old_num)+1);#}//或者使用 Number_this.children().text(Number(old_num) + 1);} else {$("#digg_tips").html(res.msg);}},});});</script>
{% endblock %}

2.后端

# 文章详情页
def article_detail(request, username, article_id):print(article_id)  # 1user_obj = models.UserInfo.objects.filter(username=username).first()print(user_obj)if not user_obj:'''图片防盗链:通过 Referer参数判断,通过这个参数就可以知道你当前的地址是从哪个网页调过来的,然后做验证   '''return render(request, '404.html')# 查询用户自己的所有文章(过滤当前站点的文章)blog = user_obj.blogarticle_detail = models.Article.objects.filter(pk=article_id).first()category_list = models.Category.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')tag_list = models.Tag.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')date_list = models.Article.objects.annotate(month=TruncMonth('create_time')).values('month').filter(blog=blog).annotate(count_article_nums=Count('pk')).values('month', 'count_article_nums')# 查询所有的评论列表comment_list = models.Comment.objects.filter(article_id=article_id).all()return render(request, 'article_detail.html', locals())

三、点赞点菜

1.前端

{% extends 'home.html' %}{% block css %}<style>.s1 {margin-right: 10px;color: #999;}.content {font-size: 18px;color: #444;}#div_digg {float: right;margin-bottom: 10px;margin-right: 30px;font-size: 12px;width: 128px;text-align: center;margin-top: 10px;}.diggit {float: left;width: 46px;height: 52px;background: url(/static/img/upup.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.buryit {float: right;margin-left: 20px;width: 46px;height: 52px;background: url(/static/img/downdown.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.clear {clear: both;}.diggword {margin-top: 5px;margin-left: 0;font-size: 12px;color: #808080;}.clearfix:focus {content: '';display: block;clear: both;}</style>
{% endblock %}{% block content %}<div class="col-md-3"><div class="panel panel-info"><div class="panel-heading">文章分类</div><div class="panel-body">{% for category in category_list %}<!-- 如果后台用的是values --><p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }} ({{ category.1 }})</a></p><!-- 如果后台用的是values -->{#                    <p><a href="/{{ username }}/category/{{ category.pk }}">{{ category.name }} ({{ category.count_article_num }})</a></p>#}{% endfor %}</div></div><div class="panel panel-success"><div class="panel-heading">文章标签</div><div class="panel-body">{% for tag in tag_list %}<p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }} ({{ tag.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-danger"><div class="panel-heading">日期归档</div><div class="panel-body">{% for date in date_list %}{#  <p><a href="">{{ date.0 }} ({{ date.1 }})</a></p> #}<p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }}({{ date.count_article_nums }})</a></p>{% endfor %}</div></div></div><div class="col-md-9"><h3 style="color: #399ab2;">{{ article_detail.title }}</h3><div class="content">{{ article_detail.content|safe }}</div><!-- 点赞点彩样式开始 --><div class="clearfix"><div id="div_digg"><div class="diggit active" onclick="votePost(11647089,'Digg')"><span class="diggnum" id="digg_count">{{ article_detail.up_num }}</span></div><div class="buryit active" onclick="votePost(11647089,'Bury')"><span class="burynum" id="bury_count">{{ article_detail.down_num }}</span></div><div class="clear"></div><div class="diggword" id="digg_tips" style="color: red;"></div></div></div><!-- 点赞点彩样式结束 --></div>{% endblock %}{% block js %}<script>// 11647089,'Digg'分别表示文章id和标志flag// 思路1:{% comment %}function votePost(id, flag) {is_up = flag === 'Digg' ? 0 : 1;}{% endcomment %}// 思路2:$(".active").click(function () {let is_up = $(this).hasClass('diggit');// 文章idvar article_id = '{{ article_detail.pk }}';var _this = $(this);// 发起Ajax请求$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up, article_id: article_id, csrfmiddlewaretoken: '{{ csrf_token }}'},success: function () {// 将标签放入文本,要么是text,要么是htmlif (res === 200) {$("#digg_tips").text(res.msg);// 如果是点赞就让点赞数加1,如果是点踩就让点踩数加1// 注意:在text()中加数据就是赋值,空就是获取值let old_num = _this.children().text();// 此时的 old_num 是string类型,需要转类型{#_this.children().text(parseInt(old_num)+1);#}//或者使用 Number_this.children().text(Number(old_num) + 1);} else {$("#digg_tips").html(res.msg);}},});});</script>
{% endblock %}

2.后端

# 点赞点彩
def up_and_down(request):'''分析点赞点彩的实现逻辑:1.必须判断用户是否登陆了。如果没有则在前端页面显示登录2.若是第一次登录:2.1 点赞数加 12.2 在页面上显示点赞成功3.如果已经点击过,就提示不让他再点了4.如果是第一次点击,应该在处理哪些逻辑4.1 肯定需要在点赞点彩表中增加一条记录4.2 还需要更新文章中的up_num或者down_num字段5. 取消点赞或者点彩功能-----》收藏:param request::return:'''if request.method == 'POST':back_dict = {'code': 200, 'msg': '支持成功'}# 1.接收参数is_up = request.POST.get('is_UP')  # stris_up = json.loads(is_up)article_id = request.POST.get('article_id')# 2.判断用户是否登录if not request.session.get('username'):back_dict['code'] = 1400back_dict['msg'] = '请先<a href="/login/" style="color: red;">登录</a>'return JsonResponse(back_dict)# 3.验证参数# 4.判断是否已经点赞过了res = models.UpAndDown.objects.filter(article_id=article_id, user_id=request.session.get('id')).first()if res:back_dict['code'] = 1401back_dict['msg'] = '你已经支持过了'return JsonResponse(back_dict)# 5.处理业务逻辑# 操作up_and_down, articleif is_up:models.Article.objects.create(pk=article_id).update(up_num=F('up_num') + 1)else:models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)back_dict['msg'] = '支持成功'# 查询出来要么点赞,要么点踩models.UpAndDown.objects.create(is_up=is_up, article_id=article_id, user_id=request.session.get('id'))return JsonResponse(back_dict)

四、评论功能

1.根评论前端

{% extends 'home.html' %}{% block css %}<style>.s1 {margin-top: 10px;color: #999;}.content {font-size: 16px;color: #444;}#div_digg {float: right;margin-bottom: 10px;margin-right: 30px;font-size: 12px;width: 128px;text-align: center;margin-top: 10px;}.diggit {float: left;width: 46px;height: 52px;background: url(/static/img/upup.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.buryit {float: right;margin-left: 20px;width: 46px;height: 52px;background: url(/static/img/downdown.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.clear {clear: both;}.diggword {margin-top: 5px;margin-left: 0;font-size: 12px;color: #808080;}{# 父标签塌陷 #}.clearfix {content: "";display: block;clear: both;}</style>
{% endblock %}{% block content %}<div class="col-md-3"><!-- 带标题的面板 --><div class="panel panel-success"><div class="panel-heading">文章分类</div><div class="panel-body">{% for cate in cate_list %}{# <p><a href="">{{ cate.name }}({{ cate.1 }})</a></p> #}<p><a href="/{{ username }}/category/{{ cate.2 }}">{{ cate.0 }}({{ cate.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-info"><div class="panel-heading">文章标签</div><div class="panel-body">{% for tag in tag_list %}<!-- tag.0是标签名称 tag.1是标签数量 -->{# <p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p> #}<p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-danger"><div class="panel-heading">日期归档</div><div class="panel-body">{% for date in date_list %}<p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }}({{ date.c }})</a></p>{% endfor %}</div></div></div><div class="col-md-9"><h3 style="color: #9cba39"><a href="">{{ article_detail.title }}</a></h3><div class="content">{{ article_detail.content|safe }}</div><!-- 点赞点踩样式开始 --><div class="clearfix"><div id="div_digg"><!-- 点赞 --><div class="diggit active" onclick="votePost(12834355,'Digg')"><span class="diggnum" id="digg_count">{{ article_detail.up_num }}</span></div><!-- 点踩 --><div class="buryit active" onclick="votePost(12834355,'Bury')"><span class="burynum" id="bury_count">{{ article_detail.down_num }}</span></div><div class="clear"></div><div class="diggword" id="digg_tips" style="color: red;"></div></div></div><!-- 点赞点踩样式结束 --><!-- 评论列表的展示开始 --><div class="comment_list"><h4><span class="glyphicon glyphicon-comment"></span>评论列表</h4><ul class="list-group">{% for comment in comment_list %}<li class="list-group-item"><span style="margin-right: 10px;">#{{ forloop.counter }}楼</span><span style="margin-right: 10px;">{{ comment.comment_time }}</span><span style="margin-right: 10px;">{{ comment.user.username }}</span><span style="margin-right: 10px;" class="pull-right"><a href="#">回复</a></span><div class="content" style="margin-left: 14px;">你好啊</div></li>{% endfor %}</ul></div><!-- 评论列表的展示结束 --><!-- 评论功能开始 --><div class="comment"><p><span class="glyphicon glyphicon-comment">发表评论</span></p><p><textarea name="" id="content" cols="30" rows="10"></textarea></p><p><button class="btn btn-success btn_comment">提交评论</button></p></div><!-- 评论功能结束 --></div>
{% endblock %}{% block js %}<script><!--点赞点踩样式开始 -->{% comment %}function onclick(id, flag) {// 方式1:{#if (flag === "Digg") {} else {}#}// 方式2:三元表达式{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}// 方式3:给class加上active绑定点击事件$(".active").click(function () {// 判断是点赞还是点踩let is_up = $(this).hasClass("diggit");// 文章idvar article_id = '{{ article_detail.pk }}'var _this = $(this);// 发起Ajax请求$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up,article_id: article_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {if (res.code === 200) {// 将文本放入标签中$("#digg_tips").text(res.msg);// 如果是点赞,就让点赞数加1,如果是点踩,就让点踩数加1// 先获取文本, 并且将字符串数字转为整型{#let old_num = parseInt(_this.children().text());#}// 或者直接使用Numberlet old_num = Number(_this.children().text());// 再给文本赋值_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 --><!-- 评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}// 1.获取参数// 获取文章idvar article_id = '{{ article_detail.pk }}';// 获取文章内容let content = $("#content").val();// 2.发起Ajax请求$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {// 评论成功后,把评论内容显示出来// 首先要做评论内容的临时渲染// 反引号是ES6中的模板语法var username = '{{ request.session.username }}';let html = `<li class="list-group-item"><span style="margin-right: 10px;"><span class="glyphicon glyphicon-comment"></span>${username}</span><div class="content" style="margin-left: 14px;">${content}</div></li>`;$(".list-group").append(html);// 清空评论框中的内容,即赋值为空(字符串空)$("#content").val('');}});});<!-- 评论功能结束 --></script>
{% endblock %}

2.根评论后端


# 评论功能
def comment(request):'''分析评论的逻辑:1.登录之后才能评论2.评论的内容要入库1.操作文章表,2.评论表:param request::return:'''back_dict = {'code': 200, 'msg': '支持成功'}# 1.接收参数article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')# 2.判断用户是否登录if not request.session.get('username'):back_dict['code'] = 1404back_dict['msg'] = '请先登录之后再评论'return JsonResponse(back_dict)# 加事务from django.db import transactiontry:with transaction.atomic():# 操作文章表models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)# 操作评论表models.Comment.objects.create(content=content, article_id=article_id,parent_id=parent_id, user_id=request.session.get('id'))except:# 加入日志...transaction.rollback()return JsonResponse(back_dict)

3.子评论前端

{% extends 'home.html' %}{% block css %}<style>.s1 {margin-top: 10px;color: #999;}.content {font-size: 16px;color: #444;}#div_digg {float: right;margin-bottom: 10px;margin-right: 30px;font-size: 12px;width: 128px;text-align: center;margin-top: 10px;}.diggit {float: left;width: 46px;height: 52px;background: url(/static/img/upup.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.buryit {float: right;margin-left: 20px;width: 46px;height: 52px;background: url(/static/img/downdown.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.clear {clear: both;}.diggword {margin-top: 5px;margin-left: 0;font-size: 12px;color: #808080;}{# 父标签塌陷 #}.clearfix {content: "";display: block;clear: both;}</style>
{% endblock %}{% block content %}<div class="col-md-3"><!-- 带标题的面板 --><div class="panel panel-success"><div class="panel-heading">文章分类</div><div class="panel-body">{% for cate in cate_list %}{# <p><a href="">{{ cate.name }}({{ cate.1 }})</a></p> #}<p><a href="/{{ username }}/category/{{ cate.2 }}">{{ cate.0 }}({{ cate.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-info"><div class="panel-heading">文章标签</div><div class="panel-body">{% for tag in tag_list %}<!-- tag.0是标签名称 tag.1是标签数量 -->{# <p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p> #}<p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-danger"><div class="panel-heading">日期归档</div><div class="panel-body">{% for date in date_list %}<p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }}({{ date.c }})</a></p>{% endfor %}</div></div></div><div class="col-md-9"><h3 style="color: #9cba39"><a href="">{{ article_detail.title }}</a></h3><div class="content">{{ article_detail.content|safe }}</div><!-- 点赞点踩样式开始 --><div class="clearfix"><div id="div_digg"><!-- 点赞 --><div class="diggit active" onclick="votePost(12834355,'Digg')"><span class="diggnum" id="digg_count">{{ article_detail.up_num }}</span></div><!-- 点踩 --><div class="buryit active" onclick="votePost(12834355,'Bury')"><span class="burynum" id="bury_count">{{ article_detail.down_num }}</span></div><div class="clear"></div><div class="diggword" id="digg_tips" style="color: red;"></div></div></div><!-- 点赞点踩样式结束 --><!-- 评论列表的展示开始 --><div class="comment_list"><h4><span class="glyphicon glyphicon-comment"></span>评论列表</h4><ul class="list-group">{% for comment in comment_list %}<li class="list-group-item"><span style="margin-right: 10px;">#{{ forloop.counter }}</span><span style="margin-right: 10px;">{{ comment.comment_time }}</span><span style="margin-right: 10px;">{{ comment.user.username }}</span><!-- href="javascript;" 防止页面跳转,这是由于锚点的缘故,若是href="" 会自动刷新页面到最上面 --><span style="margin-right: 10px;" class="pull-right"><a href="javascript:;" comment_username="{{ comment.user.username }}"comment_id="{{ comment.pk }}" class="reply">回复</a></span><div class="content" style="margin-left: 14px;"><!-- 若是根评论则直接显示评论内容,子评论需要@+当前评论者 -->{% if comment.parent %}{{ comment.content }}{% else %}<p>@ {{ comment.parent.user.username }}</p>{{ comment.content }}{% endif %}</div></li>{% endfor %}</ul></div><!-- 评论列表的展示结束 --><!-- 评论功能开始 --><div class="comment"><p><span class="glyphicon glyphicon-comment">发表评论</span></p><p><textarea name="" id="content" cols="30" rows="10"></textarea></p><p><button class="btn btn-success btn_comment">提交评论</button></p></div><!-- 评论功能结束 --></div>
{% endblock %}{% block js %}<script>{#<!--点赞点踩样式开始 -->#}{% comment %}function onclick(id, flag) {// 方式1:{#if (flag === "Digg") {} else {}#}// 方式2:三元表达式{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}// 方式3:给class加上active绑定点击事件$(".active").click(function () {// 判断是点赞还是点踩let is_up = $(this).hasClass("diggit");// 文章idvar article_id = '{{ article_detail.pk }}'var _this = $(this);// 发起Ajax请求$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up,article_id: article_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {if (res.code === 200) {// 将文本放入标签中$("#digg_tips").text(res.msg);// 如果是点赞,就让点赞数加1,如果是点踩,就让点踩数加1// 先获取文本, 并且将字符串数字转为整型{#let old_num = parseInt(_this.children().text());#}// 或者直接使用Numberlet old_num = Number(_this.children().text());// 再给文本赋值_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 -->// 定义一个全局变量,若是根评论值就是null,若是子评论,就给parent_id赋值var parent_id = null;<!-- 根评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}// 1.获取参数// 获取文章idvar article_id = '{{ article_detail.pk }}';// 获取文章内容let content = $("#content").val();if (parent_id) {// parent_id有值就代表是子评论,把评论的内容截取掉// indexOf() 是匹配到了,就返回它在字符串中的位置, 并把该值之前的内容全部截掉let indexOf_num = content.indexOf('\n');// 使用slice方法从indexOf_num这个位置开始截取,剩下的返回给contentcontent = content.slice(indexOf_num);}// 2.发起Ajax请求$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,parent_id: parent_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {// 评论成功后,把评论内容显示出来// 首先要做评论内容的临时渲染// 反引号是ES6中的模板语法var username = '{{ request.session.username }}';let html = `<li class="list-group-item"><span style="margin-right: 10px;"><span class="glyphicon glyphicon-comment"></span>${username}</span><div class="content" style="margin-left: 14px;">${content}</div></li>`;$(".list-group").append(html);// 清空评论框中的内容,即赋值为空(字符串空)$("#content").val('');}});});<!-- 根评论功能结束 --><!-- 子评论功能开始 -->$(".reply").click(function () {// 获取自定义属性comment_username以便获取usernamelet comment_username = $(this).attr('comment_username');// 给子评论的id赋值parent_id = $(this).attr('comment_id');// 获取内容,并为其设置格式和焦点,以便在页面点击回复的时候自动选中$("#content").val("@" + comment_username + '\n').focus();});<!-- 子评论功能结束 --></script>
{% endblock %}

子评论后端

# 文章详情
def article_detail(request, username, article_id):print(article_id)  # 1user_obj = models.UserInfo.objects.filter(username=username).first()print('user_obj:', user_obj)if not user_obj:'''图片防盗链:通过 Referer参数判断,通过这个参数就可以知道你当前的地址是从哪个网页调过来的,然后做验证   '''return render(request, '404.html')# 查询用户自己的所有文章(过滤当前站点的文章)blog = user_obj.blogarticle_detail = models.Article.objects.filter(pk=article_id).first()cate_list = models.Category.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')print(cate_list)  # <QuerySet [('root的分类一', 4, 1), ('root的分类二', 2, 2)]>tag_list = models.Tag.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')date_list = models.Article.objects.annotate(month=TruncMonth('create_time')).values('month').filter(blog=blog).annotate(count_article_nums=Count('pk')).values('month', 'count_article_nums')# 查询所有的评论列表,查询的是当前这篇文章的所有评论列表comment_list = models.Comment.objects.filter(article_id=article_id).all()return render(request, 'article_detail.html', locals())# 文章评论
def comment(request):'''分析评论的逻辑:1.必须登录才能评论2.评论的内容要入库1.操作文章表2.评论表:param request::return:'''if request.method == 'POST':# 1.定义返回给前端的json数据格式back_dict = {'code': 200, 'msg': '密码修改成功,3秒之后自动跳转页面', 'data': []}# 2.接收参数article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')# 3.判断用户是否登录if not request.session.get('username'):back_dict['code'] = 5001back_dict['msg'] = '请先登录之后再评论'return JsonResponse(back_dict)# 操作表必须同时成功或者同时失败,需要启用事务from django.db import transactiontry:with transaction.atomic():# 操作文章表models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)# 评论评论表models.Comment.objects.create(content=content, article_id=article_id,user_id=request.session.get('id'),parent_id=parent_id)except:# 4.记录日志ctime = datetime.datetime.today()logger = get_logger()logger.debug('{}在{}注册了账号'.format(request.session.get('username'), ctime))transaction.rollback()return JsonResponse(back_dict)

五、评论分页

1.前端

{% extends 'home.html' %}{% block css %}<style>.s1 {margin-top: 10px;color: #999;}.content {font-size: 16px;color: #444;}#div_digg {float: right;margin-bottom: 10px;margin-right: 30px;font-size: 12px;width: 128px;text-align: center;margin-top: 10px;}.diggit {float: left;width: 46px;height: 52px;background: url(/static/img/upup.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.buryit {float: right;margin-left: 20px;width: 46px;height: 52px;background: url(/static/img/downdown.gif) no-repeat;text-align: center;cursor: pointer;margin-top: 2px;padding-top: 5px;}.clear {clear: both;}.diggword {margin-top: 5px;margin-left: 0;font-size: 12px;color: #808080;}{# 父标签塌陷 #}.clearfix {content: "";display: block;clear: both;}</style>
{% endblock %}{% block content %}<div class="col-md-3"><!-- 带标题的面板 --><div class="panel panel-success"><div class="panel-heading">文章分类</div><div class="panel-body">{% for cate in cate_list %}{# <p><a href="">{{ cate.name }}({{ cate.1 }})</a></p> #}<p><a href="/{{ username }}/category/{{ cate.2 }}">{{ cate.0 }}({{ cate.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-info"><div class="panel-heading">文章标签</div><div class="panel-body">{% for tag in tag_list %}<!-- tag.0是标签名称 tag.1是标签数量 -->{# <p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p> #}<p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }}({{ tag.1 }})</a></p>{% endfor %}</div></div><div class="panel panel-danger"><div class="panel-heading">日期归档</div><div class="panel-body">{% for date in date_list %}<p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }}({{ date.c }})</a></p>{% endfor %}</div></div></div><div class="col-md-9"><h3 style="color: #9cba39"><a href="">{{ article_detail.title }}</a></h3><div class="content">{{ article_detail.content|safe }}</div><!-- 点赞点踩样式开始 --><div class="clearfix"><div id="div_digg"><!-- 点赞 --><div class="diggit active" onclick="votePost(12834355,'Digg')"><span class="diggnum" id="digg_count">{{ article_detail.up_num }}</span></div><!-- 点踩 --><div class="buryit active" onclick="votePost(12834355,'Bury')"><span class="burynum" id="bury_count">{{ article_detail.down_num }}</span></div><div class="clear"></div><div class="diggword" id="digg_tips" style="color: red;"></div></div></div><!-- 点赞点踩样式结束 --><!-- 评论列表的展示开始 --><div class="comment_list"><h4><span class="glyphicon glyphicon-comment"></span>评论列表</h4><ul class="list-group">{% for comment in comment_list %}<li class="list-group-item"><span style="margin-right: 10px;">#{{ forloop.counter }}</span><span style="margin-right: 10px;">{{ comment.comment_time }}</span><span style="margin-right: 10px;">{{ comment.user.username }}</span><!-- href="javascript;" 防止页面跳转,这是由于锚点的缘故,若是href="" 会自动刷新页面到最上面 --><span style="margin-right: 10px;" class="pull-right"><a href="javascript:;" comment_username="{{ comment.user.username }}"comment_id="{{ comment.pk }}" class="reply">回复</a></span><div class="content" style="margin-left: 14px;"><!-- 若是根评论则直接显示评论内容,子评论需要@+当前评论者 -->{% if comment.parent %}{{ comment.content }}{% else %}<p>@ {{ comment.parent.user.username }}</p>{{ comment.content }}{% endif %}</div></li>{% endfor %}</ul></div><!-- 评论列表的展示结束 --><!-- 分页功能开始 --><div class="text-center">{{ page_obj.page_html|safe }}</div><!-- 分页功能结束 --><!-- 评论功能开始 --><div class="comment"><p><span class="glyphicon glyphicon-comment">发表评论</span></p><p><textarea name="" id="content" cols="30" rows="10"></textarea></p><p><button class="btn btn-success btn_comment">提交评论</button></p></div><!-- 评论功能结束 --></div>
{% endblock %}{% block js %}<script>{#<!--点赞点踩样式开始 -->#}{% comment %}function onclick(id, flag) {// 方式1:{#if (flag === "Digg") {} else {}#}// 方式2:三元表达式{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}// 方式3:给class加上active绑定点击事件$(".active").click(function () {// 判断是点赞还是点踩let is_up = $(this).hasClass("diggit");// 文章idvar article_id = '{{ article_detail.pk }}'var _this = $(this);// 发起Ajax请求$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up,article_id: article_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {if (res.code === 200) {// 将文本放入标签中$("#digg_tips").text(res.msg);// 如果是点赞,就让点赞数加1,如果是点踩,就让点踩数加1// 先获取文本, 并且将字符串数字转为整型{#let old_num = parseInt(_this.children().text());#}// 或者直接使用Numberlet old_num = Number(_this.children().text());// 再给文本赋值_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 -->// 定义一个全局变量,若是根评论值就是null,若是子评论,就给parent_id赋值var parent_id = null;<!-- 根评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}// 1.获取参数// 获取文章idvar article_id = '{{ article_detail.pk }}';// 获取文章内容let content = $("#content").val();if (parent_id) {// parent_id有值就代表是子评论,把评论的内容截取掉// indexOf() 是匹配到了,就返回它在字符串中的位置, 并把该值之前的内容全部截掉let indexOf_num = content.indexOf('\n');// 使用slice方法从indexOf_num这个位置开始截取,剩下的返回给contentcontent = content.slice(indexOf_num);}// 2.发起Ajax请求$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,parent_id: parent_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {// 评论成功后,把评论内容显示出来// 首先要做评论内容的临时渲染// 反引号是ES6中的模板语法var username = '{{ request.session.username }}';let html = `<li class="list-group-item"><span style="margin-right: 10px;"><span class="glyphicon glyphicon-comment"></span>${username}</span><div class="content" style="margin-left: 14px;">${content}</div></li>`;$(".list-group").append(html);// 清空评论框中的内容,即赋值为空(字符串空)$("#content").val('');}});});<!-- 根评论功能结束 --><!-- 子评论功能开始 -->$(".reply").click(function () {// 获取自定义属性comment_username以便获取usernamelet comment_username = $(this).attr('comment_username');// 给子评论的id赋值parent_id = $(this).attr('comment_id');// 获取内容,并为其设置格式和焦点,以便在页面点击回复的时候自动选中$("#content").val("@" + comment_username + '\n').focus();});<!-- 子评论功能结束 --><!-- 评论分页功能开始 -->$(".btn_page").click(function () {//alert(123); // 验证后触发了// 1.获取当前是第几页let current_page = $(this).attr('current_page');var article_id = '{{ article_detail.pk }}';// 给li增加active类属性// '<li class="active"><a href="javascript:;" class="btn_page" current_page="%s">%s</a></li>' % (i, i)// 删除上一页的高亮active$(".active").removeClass('active');$(this).parent().addClass('active');// 2.直接发起Ajax请求$.ajax({url: '/comment_page/',type: 'post',data: {current_page: current_page,article_id: article_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {console.log(res);if (res.code === 200) {var html = "";  // 定义一个全局变量html,用于接收li$.each(res.data, function (index, obj) {console.log(obj);html += `<li class="list-group-item"><span style="margin-right: 10px;">#${obj.forloop}楼</span><span style="margin-right: 10px;">${obj.comment_time}</span><span style="margin-right: 10px;">${obj.username}</span><span style="margin-right: 10px;" class="pull-right"><a href="javascript:;" comment_username="${obj.username}"comment_id="${obj.pk}" class="reply">回复</a></span><div class="content" style="margin-left: 14px;"><!-- 若是根评论则直接显示评论内容,子评论需要@+当前评论者 -->${obj.content}</div></li>`;})// 将li放到ul中去$(".list-group").html(html);}},});});<!-- 评论分页功能结束 --></script>
{% endblock %}

2.后端

# 文章详情
def article_detail(request, username, article_id):print(article_id)  # 1user_obj = models.UserInfo.objects.filter(username=username).first()print('user_obj:', user_obj)if not user_obj:'''图片防盗链:通过 Referer参数判断,通过这个参数就可以知道你当前的地址是从哪个网页调过来的,然后做验证   '''return render(request, '404.html')# 查询用户自己的所有文章(过滤当前站点的文章)blog = user_obj.blogarticle_detail = models.Article.objects.filter(pk=article_id).first()cate_list = models.Category.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')print(cate_list)  # <QuerySet [('root的分类一', 4, 1), ('root的分类二', 2, 2)]>tag_list = models.Tag.objects.filter(blog=blog).annotate(count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk')date_list = models.Article.objects.annotate(month=TruncMonth('create_time')).values('month').filter(blog=blog).annotate(count_article_nums=Count('pk')).values('month', 'count_article_nums')# 查询所有的评论列表,查询的是当前这篇文章的所有评论列表comment_list = models.Comment.objects.filter(article_id=article_id).all()# 分页列表功能from utils.mypage1 import Paginationcurrent_page = request.GET.get('page')try:current_page = int(current_page)except:current_page = 1all_count = comment_list.count()page_obj = Pagination(current_page, all_count, per_page_num=5)comment_list = comment_list[page_obj.start: page_obj.end]return render(request, 'article_detail.html', locals())# 文章评论
def comment(request):'''分析评论的逻辑:1.必须登录才能评论2.评论的内容要入库1.操作文章表2.评论表:param request::return:'''if request.method == 'POST':# 1.定义返回给前端的json数据格式back_dict = {'code': 200, 'msg': '密码修改成功,3秒之后自动跳转页面', 'data': []}# 2.接收参数article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')# 3.判断用户是否登录if not request.session.get('username'):back_dict['code'] = 5001back_dict['msg'] = '请先登录之后再评论'return JsonResponse(back_dict)# 操作表必须同时成功或者同时失败,需要启用事务from django.db import transactiontry:with transaction.atomic():# 操作文章表models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)# 评论评论表models.Comment.objects.create(content=content, article_id=article_id,user_id=request.session.get('id'),parent_id=parent_id)except:# 4.记录日志ctime = datetime.datetime.today()logger = get_logger()logger.debug('{}在{}注册了账号'.format(request.session.get('username'), ctime))transaction.rollback()return JsonResponse(back_dict)# 评论列表分页功能
def comment_page(request):# 根据当前第几页查询当前页的评论列表数据if request.method == 'POST':back_dict = {'code': 200, 'msg': '查询成功'}# 接收参数current_page = request.POST.get('current_page')try:current_page = int(current_page)except:current_page = 1article_id = request.POST.get('article_id')# 验证参数if not current_page:back_dict['code'] = 6001back_dict['msg'] = '当前页数据有误或为空'JsonResponse(back_dict)# 每页显示的条数per_page_num = 5.start_page = (current_page - 1) * per_page_numend_page = current_page * per_page_num# 查询评论列表数据 查询出来的结果是queryset对象,只能在模板渲染的时候才能使用,需要使用for循环取出使用comment_list = models.Comment.objects.filter(article_id=article_id).all()[start_page: end_page]comment_list_obj = []  # [{},{},{}]i = 1for comment in comment_list:comment_list_obj.append({'forloop': i,'pk': comment.pk,'comment_time': comment.comment_time,'username': comment.user.username,'content': comment.content})i += 1print(comment_list_obj)# [{'forloop': 1, 'comment_time': datetime.datetime(2023, 8, 21, 19, 25, 54, 201246),# 'username': 'jack', 'content': '@jack\n你怎么不信呢?'}, ]back_dict['data'] = comment_list_objreturn JsonResponse(back_dict)

3.分页的代码

1.原始的分页代码

class Pagination(object):def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):"""封装分页相关数据:param current_page: 当前页:param all_count:    数据库中的数据总条数:param per_page_num: 每页显示的数据条数:param pager_count:  最多显示的页码个数"""try:current_page = int(current_page)except Exception as e:current_page = 1if current_page < 1:current_page = 1self.current_page = current_pageself.all_count = all_countself.per_page_num = per_page_num# 总页码all_pager, tmp = divmod(all_count, per_page_num)if tmp:all_pager += 1self.all_pager = all_pagerself.pager_count = pager_countself.pager_count_half = int((pager_count - 1) / 2)@propertydef start(self):return (self.current_page - 1) * self.per_page_num@propertydef end(self):return self.current_page * self.per_page_numdef page_html(self):# 如果总页码 < 11个:if self.all_pager <= self.pager_count:pager_start = 1pager_end = self.all_pager + 1# 总页码  > 11else:# 当前页如果<=页面上最多显示11/2个页码if self.current_page <= self.pager_count_half:pager_start = 1pager_end = self.pager_count + 1# 当前页大于5else:# 页码翻到最后if (self.current_page + self.pager_count_half) > self.all_pager:pager_end = self.all_pager + 1pager_start = self.all_pager - self.pager_count + 1else:pager_start = self.current_page - self.pager_count_halfpager_end = self.current_page + self.pager_count_half + 1page_html_list = []# 添加前面的nav和ul标签page_html_list.append('''<nav aria-label='Page navigation>'<ul class='pagination'>''')first_page = '<li><a href="?page=%s">首页</a></li>' % (1)page_html_list.append(first_page)if self.current_page <= 1:prev_page = '<li class="disabled"><a href="#">上一页</a></li>'else:prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)page_html_list.append(prev_page)for i in range(pager_start, pager_end):if i == self.current_page:temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)else:temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)page_html_list.append(temp)if self.current_page >= self.all_pager:next_page = '<li class="disabled"><a href="#">下一页</a></li>'else:next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)page_html_list.append(next_page)last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)page_html_list.append(last_page)# 尾部添加标签page_html_list.append('''</nav></ul>''')return ''.join(page_html_list)

2.优化后的页面不再刷新的分页代码

class Pagination(object):def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):"""封装分页相关数据:param current_page: 当前页:param all_count:    数据库中的数据总条数:param per_page_num: 每页显示的数据条数:param pager_count:  最多显示的页码个数"""try:current_page = int(current_page)except Exception as e:current_page = 1if current_page < 1:current_page = 1self.current_page = current_pageself.all_count = all_countself.per_page_num = per_page_num# 总页码all_pager, tmp = divmod(all_count, per_page_num)if tmp:all_pager += 1self.all_pager = all_pagerself.pager_count = pager_countself.pager_count_half = int((pager_count - 1) / 2)@propertydef start(self):return (self.current_page - 1) * self.per_page_num@propertydef end(self):return self.current_page * self.per_page_numdef page_html(self):# 如果总页码 < 11个:if self.all_pager <= self.pager_count:pager_start = 1pager_end = self.all_pager + 1# 总页码  > 11else:# 当前页如果<=页面上最多显示11/2个页码if self.current_page <= self.pager_count_half:pager_start = 1pager_end = self.pager_count + 1# 当前页大于5else:# 页码翻到最后if (self.current_page + self.pager_count_half) > self.all_pager:pager_end = self.all_pager + 1pager_start = self.all_pager - self.pager_count + 1else:pager_start = self.current_page - self.pager_count_halfpager_end = self.current_page + self.pager_count_half + 1page_html_list = []# 添加前面的nav和ul标签page_html_list.append('''<nav aria-label='Page navigation>'<ul class='pagination'>''')first_page = '<li><a href="?page=%s">首页</a></li>' % (1)page_html_list.append(first_page)if self.current_page <= 1:prev_page = '<li class="disabled"><a href="#">上一页</a></li>'else:prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)page_html_list.append(prev_page)for i in range(pager_start, pager_end):if i == self.current_page:temp = '<li class="active"><a href="javascript:;" class="btn_page" current_page="%s">%s</a></li>' % (i,i)else:temp = '<li><a href="javascript:;" class="btn_page" current_page="%s">%s</a></li>' % (i,i)page_html_list.append(temp)if self.current_page >= self.all_pager:next_page = '<li class="disabled"><a href="#">下一页</a></li>'else:next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)page_html_list.append(next_page)last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)page_html_list.append(last_page)# 尾部添加标签page_html_list.append('''</nav></ul>''')return ''.join(page_html_list)

相关文章:

BBS项目day04 文章详情页、点赞点菜、评论功能(根评论和子评论)、评论分页之刷新评论页面

一、路由 from django.contrib import admin from django.urls import path, re_path from app01 import views from django.views.static import serve from django.conf import settingsurlpatterns [path(admin/, admin.site.urls),# 注册path(register/, views.register)…...

【带着学Pytorch】1、pytorch的安装与入门

一、介绍与安装 1.1. pytorch优点: 上手简单:掌握语法和深度学习的概念,尤其是Numpy的使用与python的list切片有共同性。代码灵活:基本调用封装好的模块,动态图使编写更加灵活资源多: 硬件,软件,文档资料都很多。容易调试:动态运行在调试中可以观察数据的变化是否符…...

smartbi token回调获取登录凭证漏洞

2023年7月28日Smartbi官方修复了一处权限绕过漏洞。未经授权的攻击者可利用该漏洞&#xff0c;获取管理员token&#xff0c;完全接管管理员权限。 于是研究了下相关补丁并进行分析。 0x01分析结果 依据补丁分析&#xff0c;得到如下漏洞复现步骤 第一步&#xff0c;设置Engi…...

SQL注入之堆叠查询

文章目录 堆叠查询是什么&#xff1f;堆叠查询修改所有用户密码堆叠查询删除数据库恢复数据库 堆叠查询是什么&#xff1f; 在SQL中&#xff0c;分号;是用来表示一条sql语句的结束。试想一下我们在; 结束一个sql语句后继续构造下一条语句&#xff0c;会不会一起执行&#xff1f…...

java-JVM 类加载机制

JVM 类加载机制 JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;下面我们就分别来看一下这五个过程。 1.1. 加载 加载是类加载过程中的一个阶段&#xff0c;这个阶段会在内存中生成一个代表这…...

前端面试:【网络协议与性能优化】提升Web应用性能的策略

嗨&#xff0c;亲爱的Web开发者&#xff01;构建高性能的Web应用是每个开发者的梦想。本文将介绍一些性能优化策略&#xff0c;包括资源加载、懒加载和CDN等&#xff0c;以帮助你提升Web应用的性能。 1. 性能优化策略&#xff1a; 压缩资源&#xff1a; 使用Gzip或Brotli等压缩…...

前端面试:【React】构建现代Web的利器

嘿&#xff0c;亲爱的React探险家&#xff01;在前端开发的旅程中&#xff0c;有一个神奇的库&#xff0c;那就是React。React是一个用于构建现代Web应用的强大工具&#xff0c;它提供了组件化开发、状态管理、生命周期管理和虚拟DOM等特性&#xff0c;让你的应用开发变得更加高…...

使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。

1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 拉取mysql:5.6和owncloud的镜像和生成实例 [rootlocalhost ~]# docker pull mysql:5.6 [rootlocalhost ~]# docker pull ownclound [rootlocalhost ~]# docker run -d --name mydb1 --env MYSQL_ROOT_PASSWO…...

k8s发布应用

前言 首先以SpringBoot应用为例介绍一下k8s的发布步骤。 1.从代码仓库下载代码&#xff0c;比如GitLab&#xff1b; 2.接着是进行打包&#xff0c;比如使用Maven&#xff1b; 3.编写Dockerfile文件&#xff0c;把步骤2产生的包制作成镜像&#xff1b; 4.上传步骤3的镜像到…...

微信小程序教学系列(4)

微信小程序教学系列 第四章&#xff1a;小程序优化与调试 1. 性能优化技巧 在开发微信小程序时&#xff0c;我们可以采取一些性能优化技巧&#xff0c;以提升小程序的性能表现和用户体验。以下是一些常用的性能优化技巧&#xff1a; 减少网络请求&#xff1a;尽量合并网络请…...

Netty核心源码解析(三)--NioEventLoop

NioEventLoop介绍 NioEventLoop继承SingleThreadEventLoop,核心是一个单例线程池,可以理解为单线程,这也是Netty解决线程并发问题的最根本思路--同一个channel连接上的IO事件只由一个线程来处理,NioEventLoop中的单例线程池轮询事件队列,有新的IO事件或者用户提交的task时便执…...

Vue2学习笔记のVue核心

目录 Vue核心初识VueVue模板语法数据绑定el与data的两种写法MVVM模型数据代理Object.defineProperty方法何为数据代理Vue中的数据代理 事件处理事件的基本使用事件修饰符键盘事件 计算属性姓名案例_插值语法实现姓名案例_methods实现姓名案例_计算属性实现姓名案例_计算属性简写…...

把matlab的m文件打包成单独的可执行文件

安装Matlab Compiler Adds-on在app里找到Application Compiler 选择要打包的文件matlab单独的运行程序的话需要把依赖的库做成runtime. 这里有两个选项. 上面那个是需要对方在联网的情况下安装, 安装包较小.下面那个是直接把runtime打包成安装程序, 大概由你的程序依赖的库的多…...

redis 6个节点(3主3从),始终一个节点不能启动

redis节点&#xff0c;始终有一个节点不能启动起来 1.修改了配置文件 protected-mode no&#xff0c;重启 修改了配置文件 protected-mode no&#xff0c;重启redis问题依然存在 2、查看/var/log/message的redis日志 Aug 21 07:40:33 redisMaster kernel: Out of memory: K…...

单体架构 Monolithic Architecture

单体架构&#xff08;Monolithic Architecture&#xff09; 单体架构是一种传统的软件架构模式&#xff0c;其中整个应用程序被构建为一个单一、完整的代码库和部署单元。 在单体架构中&#xff0c;所有的功能、模块和组件都打包在一起&#xff0c;通常使用同一种编程语言和技…...

HCIP的STP总结

目录 一、802.1D 一个交换网络内仅存在一棵生成树实例&#xff1b; 二、PVST cisco私有 基于vlan的生成树协议 三、PVST 在PVST的基础&#xff0c;兼容802.1q的trunk封装&#xff1b;且设计了部分的加速&#xff1b; 四、快速生成树 五、MSTP/MST/802.1S …...

Post Robot

一、题目 DT is a big fan of digital products. He writes posts about technological products almost everyday in his blog. But there is such few comments of his posts that he feels depressed all the day. As his best friend and an excellent programmer, DT as…...

HTML中,常用的布局方式

在HTML中&#xff0c;常用的布局方式有以下几种&#xff1a; 表格布局: 使用<table>、<tr>和<td>元素来创建一个表格布局。这种布局方式简单易懂&#xff0c;适用于需要展示数据的情况。但是不建议在网页布局中频繁使用表格布局&#xff0c;因为其结构较为复…...

uboot源码结构

一、uboot源码获取 uboot源码下载 http://www.denx.de/wiki/U-Boot/ uboot版本命名 前期:uboot-1.2.3 现在:uboot-2008.01 uboot版本选择 支持对应的硬件平台 相对成熟的版本&#xff08;资料多&#xff09; 二、uboot特点 代码结构清晰 支持丰富的处理器与开发板&#xf…...

c++(8.23)类,this指针,构造函数,析构函数,拷贝构造函数

设计一个Per类&#xff0c;类中包含私有成员&#xff1a;姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员&#xff1a;成绩、Per类对象 p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>u…...

前端网络相关知识(TCP和UDP的区别, TCP的三次握手)

tcp和udp的区别 TCP&#xff08;传输控制协议&#xff09;和UDP&#xff08;用户数据报协议&#xff09;是两种常用的互联网传输协议。它们在以下几个方面有所不同&#xff1a; 连接性&#xff1a;TCP是面向连接的协议&#xff0c;而UDP是无连接的协议。TCP在通信之前需要建立…...

大数据-玩转数据-Flink营销对账

一、说明 在电商网站中&#xff0c;订单的支付作为直接与营销收入挂钩的一环&#xff0c;在业务流程中非常重要。对于订单而言&#xff0c;为了正确控制业务流程&#xff0c;也为了增加用户的支付意愿&#xff0c;网站一般会设置一个支付失效时间&#xff0c;超过一段时间不支…...

中英双语对话大语言模型:ChatGLM-6B

介绍 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&#xff09;。…...

MES生产报工管理

一、MES生产报工管理的定义与功能&#xff1a; MES生产报工管理是指利用制造执行系统&#xff08;MES&#xff09;对生产过程进行实时监控、数据采集和分析&#xff0c;并及时记录和报告生产工单的实际完成情况。其主要功能包括&#xff1a; 1. 实时数据采集&#xff1a;通过…...

五、修改官方FreeRTOS例程(STM32F1)

1、官方源码下载 (1)进入FreeRTOS官网&#xff1a;FreeRTOS官网 (2)下载FreeRTOS。(选择带示例的下载) 2、删减目录 (1)下载后解压的FreeRTOS文件如下图所示。 (2)删除下图中红框勾选的文件。 FreeRTOS-Plus&#xff0c;FreeRTOS的生态文件&#xff0c;非必需的。tools&…...

pytorch基础实践-数据与预处理

文章目录 数据集Fashion-MNIST 数据集 数据预处理包的导入在Pytorch中进行 ETL利用torchvison包获取和处理数据集&#xff08;ET&#xff09; 访问数据集访问和查看 train_set 中的单个数据利用 DataLoader 成批访问数据 数据集 Fashion-MNIST 数据集 MNIST MNIST&#xff0c;…...

Java智慧工地系统源码(微服务+Java+Springcloud+Vue+MySQL)

智慧工地系统是依托物联网、互联网、AI、可视化建立的大数据管理平台&#xff0c;是一种全新的管理模式&#xff0c;能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。围绕施工现场管理的人、机、料、法、环五大维度&#xff0c;以及施工过程管理的进度、质量、安全三…...

PV3D: A 3D GENERATIVE MODEL FOR PORTRAITVIDEO GENERATION 【2023 ICLR】

ICLR&#xff1a;International Conference on Learning Representations CCF-A 国际表征学习大会&#xff1a;深度学习的顶级会议 生成对抗网络(GANs)的最新进展已经证明了生成令人惊叹的逼真肖像图像的能力。虽然之前的一些工作已经将这种图像gan应用于无条件的2D人像视频生…...

Apache BeanUtils工具介绍

beanutils&#xff0c;顾名思义&#xff0c;是java bean的一个工具类&#xff0c;可以帮助我们方便的读取(get)和设置(set)bean属性值、动态定义和访问bean属性&#xff1b;细心的话&#xff0c;会发现其实JDK已经提供了一个java.beans包&#xff0c;同样可以实现以上功能&…...

java 原子操作 笔记

目录 java 变量原子操作 java byte[] 原子操作 java 变量原子操作 public class Counter {private int count 0;public synchronized void increment() {count;}public synchronized int getCount() {return count;} } java byte[] 原子操作 public class SharedArray {pr…...

wordpress更换网站logo/北京网站seo招聘

教程&#xff1a; 1、下载解压安装包&#xff0c;双击主程序开始安装&#xff0c;选择安装语言&#xff1b; 2、进入安装引导&#xff0c;点击【前进】&#xff1b; 3、接受软件许可协议&#xff0c;点击【我接受】&#xff0c;点击【前进】&#xff1b; 4、软件安装目录选择…...

web技术的网站开发/服务推广软文

机械迷城手机免费版完整版下载手游是一款拥有十分独特的铅笔画风制作的冒险解密手机游戏。游戏讲述了一个需要不断对付各种黑帽黑帮的小机器的故事。这里的许多角色都是机器人设计的&#xff0c;所以你需要拯救你的女朋友。与此同时&#xff0c;你将不断地与更多的坏人打交道&a…...

建设工程合同范本 政府网站/100个商业经典案例

加载图像(用cv::imread)imread功能是加载图像文件成为一个Mat对象 其中第一个参数表示图像文件名称第二个参数 表示加载的图像是什么类型 支持常见的三个参数值IMREAD_UNCHANGE(<0)表示加载原图 不做任何改变IMREAD_GRAYSCALE(0)表示把原图作为灰度图像加载进来IMREAD_COLOR…...

手机营销型网站建设/手游代理加盟哪个平台最强大

我正在为数据库实现一个漂亮的基本搜索引擎&#xff0c;用户可能会在其中包含不同类型的信息。搜索本身由几个联合组成&#xff0c;选择结果总是合并到3列中。然而&#xff0c;返回的数据正在从不同的表中获取。每个查询使用$ term进行匹配&#xff0c;我将其绑定到“&#xff…...

建设银行官网网站首页纪念币预约/深圳白帽优化

CONVERT_TZ(dt,from_tz,to_tz)转换datetime值dt&#xff0c;从 from_tz 由给定转到 to_tz 时区给出的时区&#xff0c;并返回的结果值。 如果参数无效该函数返回NULL。mysql> SELECT CONVERT_TZ(2004-01-01 12:00:00,GMT,MET);--------------------------------------------…...

北京各大网站推广服务公司/南京网站推广排名

每一个业务系统都会根据业务需要配置各种各样的权限&#xff0c;实现方式也是千差万别&#xff0c;各有各的优缺点。今天我们 利用反射来做一个小的权限管理Demo。也可以说是插件化的权限管理&#xff0c;通用的插件化框架是实现一个接口或者协定&#xff0c; 我们的做法是先展…...