一、路由
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.*)', serve, {'document_root': settings.MEDIA_ROOT}),
re_path('(?P\w+)/(?P\d+)', views.article_detail),
path('up_and_down/', views.up_and_down),
path('comment/', views.comment),
re_path('(?P\w+)/(?Pcategory|tag|archive)/(?P.*)', views.site),
re_path('(?P\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'] = '请先登录'
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-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 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>
<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>
{% 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);
}
},
});
});
var parent_id = null;
<!-- 评论功能开始 -->
$(".comment_content").click(function () {
var article_id = '{{ article_detail.pk }}';
var content = $('#content').val();
if (parent_id) {
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) {
var username = '{{ request.session.username }}';
var html = `
${username}
${content}
`
$(".list-group").append(html)
$('#content').val('')
},
});
});
<!-- 评论功能结束 -->
<!-- 子评论功能开始 -->
$(".repay").click(function () {
let comment_username = $(this).attr('comment_username');
parent_id = $(this).attr("comment_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': '支持成功'}
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)