一、路由
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),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+)/(?P<condition>category|tag|archive)/(?P<param>.*)', views.site),re_path('(?P<username>\w+)/(?P<article_id>\d+)', views.article_detail),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 %}<p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }} ({{ category.1 }})</a></p>{# <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>{% comment %}function votePost(id, flag) {is_up = flag === 'Digg' ? 0 : 1;}{% endcomment %}$(".active").click(function () {let is_up = $(this).hasClass('diggit');var article_id = '{{ article_detail.pk }}';var _this = $(this);$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up, article_id: article_id, csrfmiddlewaretoken: '{{ csrf_token }}'},success: function () {if (res === 200) {$("#digg_tips").text(res.msg);let old_num = _this.children().text();{#_this.children().text(parseInt(old_num)+1);#}_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) user_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 %}<p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }} ({{ category.1 }})</a></p>{# <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>{% comment %}function votePost(id, flag) {is_up = flag === 'Digg' ? 0 : 1;}{% endcomment %}$(".active").click(function () {let is_up = $(this).hasClass('diggit');var article_id = '{{ article_detail.pk }}';var _this = $(this);$.ajax({url: '/up_and_down/',type: 'post',data: {is_up: is_up, article_id: article_id, csrfmiddlewaretoken: '{{ csrf_token }}'},success: function () {if (res === 200) {$("#digg_tips").text(res.msg);let old_num = _this.children().text();{#_this.children().text(parseInt(old_num)+1);#}_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': '支持成功'}is_up = request.POST.get('is_UP') is_up = json.loads(is_up)article_id = request.POST.get('article_id')if not request.session.get('username'):back_dict['code'] = 1400back_dict['msg'] = '请先<a href="/login/" style="color: red;">登录</a>'return JsonResponse(back_dict)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)if 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 %}{# <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) {{#if (flag === "Digg") {} else {}#}{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}$(".active").click(function () {let is_up = $(this).hasClass("diggit");var article_id = '{{ article_detail.pk }}'var _this = $(this);$.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);{#let old_num = parseInt(_this.children().text());#}let old_num = Number(_this.children().text());_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 --><!-- 评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}var article_id = '{{ article_detail.pk }}';let content = $("#content").val();$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {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': '支持成功'}article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')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) {{#if (flag === "Digg") {} else {}#}{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}$(".active").click(function () {let is_up = $(this).hasClass("diggit");var article_id = '{{ article_detail.pk }}'var _this = $(this);$.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);{#let old_num = parseInt(_this.children().text());#}let old_num = Number(_this.children().text());_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 -->var parent_id = null;<!-- 根评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}var article_id = '{{ article_detail.pk }}';let content = $("#content").val();if (parent_id) {let indexOf_num = content.indexOf('\n');content = content.slice(indexOf_num);}$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,parent_id: parent_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {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 () {let comment_username = $(this).attr('comment_username');parent_id = $(this).attr('comment_id');$("#content").val("@" + comment_username + '\n').focus();});<!-- 子评论功能结束 --></script>
{% endblock %}
子评论后端
def article_detail(request, username, article_id):print(article_id) user_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) 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':back_dict = {'code': 200, 'msg': '密码修改成功,3秒之后自动跳转页面', 'data': []}article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')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: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) {{#if (flag === "Digg") {} else {}#}{#var is_up = flag === 'Digg' ? 0 : 1;#}}{% endcomment %}$(".active").click(function () {let is_up = $(this).hasClass("diggit");var article_id = '{{ article_detail.pk }}'var _this = $(this);$.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);{#let old_num = parseInt(_this.children().text());#}let old_num = Number(_this.children().text());_this.children().text(old_num + 1);} else {$("#digg_tips").html(res.msg)}}});});<!-- 点赞点踩样式结束 -->var parent_id = null;<!-- 根评论功能开始 -->$(".btn_comment").click(function () {{#alert(123);#}var article_id = '{{ article_detail.pk }}';let content = $("#content").val();if (parent_id) {let indexOf_num = content.indexOf('\n');content = content.slice(indexOf_num);}$.ajax({url: '/comment/',type: 'post',data: {article_id: article_id,content: content,parent_id: parent_id,csrfmiddlewaretoken: '{{ csrf_token }}'},success: function (res) {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 () {let comment_username = $(this).attr('comment_username');parent_id = $(this).attr('comment_id');$("#content").val("@" + comment_username + '\n').focus();});<!-- 子评论功能结束 --><!-- 评论分页功能开始 -->$(".btn_page").click(function () {let current_page = $(this).attr('current_page');var article_id = '{{ article_detail.pk }}';$(".active").removeClass('active');$(this).parent().addClass('active');$.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 = ""; $.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>`;})$(".list-group").html(html);}},});});<!-- 评论分页功能结束 --></script>
{% endblock %}
2.后端
def article_detail(request, username, article_id):print(article_id) user_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) 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':back_dict = {'code': 200, 'msg': '密码修改成功,3秒之后自动跳转页面', 'data': []}article_id = request.POST.get('article_id')content = request.POST.get('content')parent_id = request.POST.get('parent_id')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: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_numcomment_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)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_numall_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):if self.all_pager <= self.pager_count:pager_start = 1pager_end = self.all_pager + 1else:if self.current_page <= self.pager_count_half:pager_start = 1pager_end = self.pager_count + 1else: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 = []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_numall_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):if self.all_pager <= self.pager_count:pager_start = 1pager_end = self.all_pager + 1else:if self.current_page <= self.pager_count_half:pager_start = 1pager_end = self.pager_count + 1else: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 = []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)