文章详情页
渲染文章内容
侧边栏有分类显示
通过设置路由的方式 传递参数 文章id 作者用户名
文章是通过文章对象渲染到前端的,所以你点击文章时也可以告诉后端你点击的是哪一篇文章
路由设置
path('<str:username>/p/<str:article_id>/', views.article),
后端代码
通过前端传递的参数 拿到作者对象 和文章对象
通过orm分组查询方法 拿到每个分类下文章数量 和 每个标签 每个时间段下的文章
def article(request, username, article_id):
# 提交评论时的操作
if request.method == 'POST':
text = request.POST.get('text')
article_id = request.POST.get('article_pk')
name = request.POST.get('name')
parent_id = request.POST.get('parent_id')
print(parent_id)
name_id = models.UserInfo.objects.filter(username=name).first().id
models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)
models.Comment.objects.create(content=text, article_id=article_id, user_id=name_id, parent_id=parent_id)
back_dict = {'msg': '评论成功'}
return JsonResponse(back_dict)
# 渲染文章详情页
user_obj = models.Site.objects.filter(name=username).first()
category_list = models.Category.objects.filter(site=user_obj).annotate
(article_num=Count("article__pk")).values( 'name', 'article_num', 'pk')
# 拿到分类列表 根据外键关联站点 拿到站点下的所有分类 根据分类分组查询每个分类下的文章数量
tag_list = models.Tag.objects.filter(site=user_obj).annotate
(article_num=Count("article__pk")).values('name','article_num','pk')
# 拿到所有标签 通过外键关联标签 然后根据标签进行分组 统计分组下所有的分组数量
time_list = models.Article.objects.filter(site=user_obj).annotate
(month=TruncMonth('create_time')).values('month').annotate(
article_num=Count("pk")).values('month', 'article_num')
# 拿到所有时间 针对文章时间进行分组 分组后 再次分组 通过月份分组 然后统计每个月份
# 下的所有文章数量
article_obj = models.Article.objects.filter(id=article_id).first()
comment_list = models.Comment.objects.filter(article_id=article_obj)
return render(request, 'articlePage.html', locals())
前端代码
网页继承了首页的顶部导航
接收后端传递的对象列表 统计侧边栏数据展示
{% extends 'homePage.html' %}
{% block title %}
{{ user_obj.name }}
{% endblock %}
{% block css %}
{% endblock %}
# 文章侧边栏渲染
{% block content %}
<div class="col-md-2">
<div class="panel panel-default">
<div class="panel-heading text-center">文章分类</div>
<div class="panel-body text-center" style="height: 200px">
{% for category in category_list %}
<p><a href="/{{ user_obj.name }}/category/{{ category.pk }}/"STYLE="color: #4cb3fa">{{ category.name }}({{ category.article_num }})</a></p>
# 分类名称(文章数量)
{% endfor %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading text-center">文章标签</div>
<div class="panel-body" style="height: 200px">
<div class="panel-body text-center" style="height: 200px">
{% for tag in tag_list %}
<p><a href="/{{ user_obj.name }}/tag/{{ tag.pk }}/" STYLE="color: #4cb3fa">{{ tag.name }}({{ tag.article_num }})</a></p>
# 标签名称(文章数量)
{% endfor %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading text-center">日期归档</div>
<div class="panel-body" style="height: 200px">
<div class="panel-body text-center" style="height: 200px">
{% for time in time_list %}
<p><a href="/{{ user_obj.name }}/archive/{{ time.month|date:'Y-m' }}/"STYLE="color: #4cb3fa">{{ time.month|date:'Y-m' }}({{ time.article_num }})</a></p>
# 时间渲染 年月(文章数量)
{% endfor %}
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div class="media">
<h2 class="media-heading"
style="margin-bottom: 14px;margin-left: 8px">{{ article_obj.title }}</h2>
# 文章标题渲染
<div class="media-body" style="padding-left: 10px">
{{ article_obj.content|safe }}
</div>
# 文章内容渲染
<div style="padding-top: 18px">
<p>
<span style="font-size: 12px;color: #999999"> {{ article_obj.create_time|date:'Y-m-d H:i' }}</span>
<span style="font-size: 12px;color: #999999"> 点赞:{{ article_obj.up_num }}</span>
<span style="font-size: 12px;color: #999999"> 反对:{{ article_obj.down_num }}</span>
<span style="font-size: 12px;color: #999999"> 评论:{{ article_obj.comment_num }}</span>
</p>
</div>
</div>
<hr>
{# 展示文章已有评论 #}
<p STYLE="margin-bottom: 30PX;font-size: 18px;color: #999999">文章评论:</p>
{% if comment_list %}
{% for comment_obj in comment_list %}
<span style="color: #999999">#{{ forloop.counter }}楼 <a
href="/{{ comment_obj.user.username }}/">{{ comment_obj.user.username }}</a>
{{ comment_obj.create_time|date:'Y-m-d H:i' }} </span>
{% if request.user.is_authenticated %}
<span><a href="#" style="margin-left: 40px" class="reply"
username="{{ comment_obj.user.username }}" parent_id="{{ comment_obj.pk }}">回复</a></span>
{% endif %}
<p style="margin-top: 10px;font-size: 14px;color: #616161">{{ comment_obj.content }}</p>
<hr>
{% endfor %}
{% else %}
<span style="color: #999999;margin-left: 8px;">该文章暂无评论</span>
{% endif %}
{% if request.user.is_authenticated %}
{# 展示评论框 #}
<div class="row">
<div class="col-md-6">
<textarea class="form-control" rows="3" id="text" style="height: 140px;margin-top: 20px"
placeholder="请输入内容..."></textarea>
<button class="text-center" style="margin-top: 20px;" id="button">发布评论</button>
<span style="color: #fa7373" id="a001"></span>
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block script %}
<script>
let parent = null
$('.reply').click(function () {
let username = '@' + $(this).attr('username') + '\n';
$('#text').val(username).focus();
parent = $(this).attr('parent_id')
})
$('#button').click(function () {
let text = $('#text').val()
if (!text) {
$('#a001').text('评论不可以为空')
} else {
$.ajax({
url: '',
type: 'post',
data: {
'text': text, 'article_pk': '{{ article_obj.pk }}', 'csrfmiddlewaretoken': '{{ csrf_token }}',
'name': '{{request.user.username}}','parent_id':parent
},
success: function (args) {
$('#a001').text(args.msg)
window.location.reload()
}
})
{# 发送ajax请求给存储评论的路由 #}
}
{# text就是评论的具体内容 #}
})
$('.upordown').click(function () {
let isup = $(this).hasClass('diggit')
if (isup) {
$.ajax({
url: '/up_or_down/',
type: 'post',
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'article_pk': '{{ article_obj.pk }}',
'isup': isup
},
success: function (args) {
$('#span').text(args.msg)
if (args.code === 10000) {
let num = Number($('#upup_count').val()) + 1;
$('#upup_count').text(num)
} } }) } else {
$.ajax({
url: '/up_or_down/',
type: 'post',
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'article_pk': '{{ article_obj.pk }}',
'isup': isup
},
success: function (args) {
$('#span').text(args.msg)
if (args.code === 10001) {
let num = Number($('#downdown_count').val()) + 1;
$('#downdown_count').text(num)
}}})}})
</script>
{% endblock %}
点赞点踩功能
前端渲染 可直接复制别人css样式和html代码
<style>
#div_digg {
float: contour;
margin-left: 8px;
margin-right: 30px;
font-size: 12px;
width: 125px;
text-align: center;
margin-top: 20px;
}
.diggit {
float: left;
width: 46px;
height: 52px;
background: url('/media/upup.gif') no-repeat;
text-align: center;
cursor: pointer;
margin-top: 2px;
padding-top: 5px;
}
.buryit {
float: left;
margin-left: 20px;
width: 46px;
height: 52px;
background: url('/media/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;
}
</style>
{# 点赞样式开启 #}
<div id="div_digg" class="text-center">
<div class="diggit upordown" id="upup">
<span class="diggnum" id="upup_count">{{ article_obj.up_num }}</span>
</div>
<div class="buryit upordown" id="downdown">
<span class="burynum" id="downdown_count">{{ article_obj.down_num }}</span>
</div>
<div class="clear"></div>
<div class="diggword" id="digg_tips">
</div>
</div>
<div style="margin-top: 10px"><span id="span"
style="color: #f58282;padding-top: 10px;font-size: 14px"></span></div>
{# 点赞样式结束 #}
<script>
$('.upordown').click(function () {
# 通过查询属性值绑定事件
let isup = $(this).hasClass('diggit')
# 通过区分calss属性值来判断是点赞还是点踩
if (isup) {
$.ajax({
url: '/up_or_down/',
# 针对这个功能 单独开一个路由
type: 'post',
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'article_pk': '{{ article_obj.pk }}',
'isup': isup
# 发送布尔值到后端 ture false代表踩
},
success: function (args) {
$('#span').text(args.msg)
if (args.code === 10000) {
let num = Number($('#upup_count').val()) + 1;
# 时时改变前端展示值 对标签数据进行加一
# 只是前端展示改变 没有做后端数据请求优化性能
$('#upup_count').text(num)
}}})} else {
$.ajax({
url: '/up_or_down/',
type: 'post',
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'article_pk': '{{ article_obj.pk }}',
'isup': isup
},
success: function (args) {
$('#span').text(args.msg)
if (args.code === 10001) {
let num = Number($('#downdown_count').val()) + 1;
$('#downdown_count').text(num)
}}})}})
</script>
后端代码
指定一个空字典 用来返回给前端回应ajax请求
1.判断用户是否登录
2.判断文章是否是用户自己的
3.判断用户是否已经对该文件进行过操作
4.录入数据 对文章的点赞数普通字段自增一 这里用到了F方法
5.点赞点踩表创建数据 哪个用户对哪个文章进行了点赞还是点踩
@login_required(login_url='/login/')
def up_or_down_func(request):
back_dict = {'msg': ''}
if request.user.is_authenticated:
if request.method == 'POST':
article_id = request.POST.get('article_pk')
isup = request.POST.get('isup')
# 判断是否是自己的文章 自己不能给自己点赞
if models.UserInfo.objects.filter(site__article__pk=article_id).first() == request.user:
back_dict['msg'] = '不能给自己的文章操作'
# 判断是否已经对这个文章进行过操作
elif models.Up_and_Down.objects.filter(user_id=request.user.id).filter(article_id=article_id):
back_dict['msg'] = '您已经评价过了'
else:
isup = json.loads(isup)
if isup:
back_dict['msg'] = '点赞成功'
back_dict['code'] = 10000
models.Article.objects.filter(pk=article_id).update(up_num=F('up_num') + 1)
else:
back_dict['msg'] = '反对成功'
back_dict['code'] = 10001
models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
models.Up_and_Down.objects.create(user_id=request.user.id, article_id=article_id, is_up=isup)
# 开始录入点赞数据
else:
back_dict['msg'] = '请先登录'
return JsonResponse(back_dict)
标签:obj,text,django,pk,num,详情,点赞,article,id
From: https://www.cnblogs.com/moongodnnn/p/17035266.html