当前位置: 首页 > 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}),# 文章详情页re_path('(?P<username>\w+)/(?P<article_id>\d+)', views.article_detail),# 点赞点彩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+)', 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-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 class="comment_list"><h3><span class="glyphicon glyphicon-comment"></span>评论列表</h3><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.parent.user.username }}</span>#}<!-- 根评论 --><span style="margin-right: 10px;">{{ comment.user.username }}</span><!-- 若是页面有滚动轮,则 a 标签中的 href 不能用 #,否则页面会调到开头,应该用javascript:; 这是因为锚点的缘故 --><span style="margin-right: 10px;" class="pull-right"><a href="javascript:;" comment_username="{{ comment.user.username }}"comment_id="{{ comment.pk }}" class="repay">回复</a></span><div class="content" style="margin-left: 14px;">{% if comment.parent %}{{ comment.content }}{% else %}<!-- @用户名 评论的内容 --><p>@ {{ comment.parent.user.username }}</p><p>{{ comment.content }}</p>{% 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 comment_content">提交评论</button></p></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);}},});});// 定义一个全局变量 parent_id// 若为空则是根评论,有值就是子评论var parent_id = null;<!-- 评论功能开始 -->$(".comment_content").click(function () {// 1.获取参数var article_id = '{{ article_detail.pk }}';// 2.获取评论的内容var content = $('#content').val();// 3.判断是根评论还是子评论if (parent_id) {// 有值就是子评论// indexOf 若匹配到了则返回它在字符串中的位置let sub_number = content.indexOf('\n' + '');// 拿到截取之后的内容content = content.slice(sub_number);}$.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 }}';var 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('')},});});<!-- 评论功能结束 --><!-- 子评论功能开始 -->$(".repay").click(function () {// 获取自定义属性comment_usernamelet comment_username = $(this).attr('comment_username');// 获取子评论的 parent_idparent_id = $(this).attr("comment_id");// 根据评论框 textarea的id属性,设置回复格式焦点,并且换行$("#content").val('@' + comment_username + '\n').focus();});<!-- 子评论功能结束 --></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)
http://www.lryc.cn/news/130523.html

相关文章:

  • el-table分页后序号连续的两种方法
  • Nginx反向代理技巧
  • kafka--kafka的基本概念-副本概念replica
  • css伪元素实现li列表圆点相连+锚点跳转悬浮窗实现
  • IronPDF for .NET Crack
  • 【C++进阶】继承、多态的详解(多态篇)
  • excel快速选择数据、选择性粘贴、冻结单元格
  • 【数仓建设系列之一】什么是数据仓库?
  • Vue2-配置脚手架、分析脚手架、render函数、ref属性、props配置项、mixin配置项、scoped样式、插件
  • VS2015项目中,MFC内存中调用DLL函数(VC6生成的示例DLL)
  • 人流目标跟踪pyqt界面_v5_deepsort
  • angular 子组件ngOnChanges监听@input传入的输入属性
  • 移植PeerTalk开源库IOS的USB通信监听服务到QT生成的FFmpeg工程
  • PHREEQC模型化学热力学理论和数据库.dat、各种模拟反应平衡反应模拟、化学动力模拟、反应迁移模拟
  • centos下使用jemalloc解决Mysql内存泄漏问题
  • 【100天精通python】Day41:python网络爬虫开发_爬虫基础入门
  • 开源和自研——机器人
  • 【AIGC 讯飞星火 | 百度AI|ChatGPT| 】智能对比
  • Wazuh安装及使用
  • docker pull 设置代理 centos
  • 仪表板展示 | DataEase看中国:2023年中国电影市场分析
  • 在APP中如何嵌入小游戏?
  • 神经网络基础-神经网络补充概念-02-逻辑回归
  • DICOM图像的常用一些参数解析
  • Java虚拟机(JVM):虚拟机栈溢出
  • MySQL流程控制
  • 智安网络|深入比较:Sass系统与源码系统的差异及选择指南
  • Day14 01-Shell脚本编程详解
  • NVIDIA GPU驱动和CUDA工具包 Linux CentOS 7 在线安装指南
  • Php“牵手”拼多多商品详情页数据采集方法,拼多多API接口申请指南