一、路由
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 settings
urlpatterns = [
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.blog
article_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 点赞数加 1
2.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'] = 1400
back_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'] = 1401
back_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'] = 1404
back_dict['msg'] = '请先登录之后再评论'
return JsonResponse(back_dict)
from django.db import transaction
try:
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.blog
article_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'] = 5001
back_dict['msg'] = '请先登录之后再评论'
return JsonResponse(back_dict)
from django.db import transaction
try:
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.blog
article_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 Pagination
current_page = request.GET.get('page')
try:
current_page = int(current_page)
except:
current_page = 1
all_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'] = 5001
back_dict['msg'] = '请先登录之后再评论'
return JsonResponse(back_dict)
from django.db import transaction
try:
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 = 1
article_id = request.POST.get('article_id')
if not current_page:
back_dict['code'] = 6001
back_dict['msg'] = '当前页数据有误或为空'
JsonResponse(back_dict)
per_page_num = 5.
start_page = (current_page - 1) * per_page_num
end_page = current_page * per_page_num
comment_list = models.Comment.objects.filter(article_id=article_id).all()[start_page: end_page]
comment_list_obj = []
i = 1
for 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 += 1
print(comment_list_obj)
back_dict['data'] = comment_list_obj
return 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 = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
else:
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
else:
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_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 = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
else:
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
else:
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_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)