一、点赞和踩灭
1、事务
事务:要么同时发生,要么同时不发生,文章点赞表增加一条数据的时候,对应的文章的点赞或者踩灭数加1,如果后面的if语句不能执行,则根据事务,点赞表也不会增加数据
from django.db import transaction #引入transaction事务
with transaction.atomic():
obj = ArticleUpDown.objects.create(user_id=user_pk, article_id=article_id, is_up=is_up) #文章点赞表里面添加一条数据
if is_up:
Article.objects.filter(pk=article_id).update(up_count=F("up_count") + 1) #文章表相应的文章的点赞数加1
else:
Article.objects.filter(pk=article_id).update(down_count=F("down_count") + 1) #文章表相应的文章的踩灭数加1
2、render方法
浏览器给服务器发送一个请求,视图函数从模板中取到html页面,如果页面里面有模板语法,如{{ }}、{% %},render方法会先对其进行渲染,将模板语法替换为相应的html标签,
最后将标签返回给浏览器,所以如果js在html页面,那么就可以使用模板语法,而如果将js单独做成一个静态文件,则不能使用模板语法。
3、点赞的视图函数和页面
views.py文件增加点赞视图:
import json
from django.http import JsonResponse
from django.db.models import F
from django.db import transaction
def digg(request):
res={"state":True} #状态为true代表点赞,false为踩灭
user_pk=request.user.pk # 当前登录用户,即点赞用户,request.user是全局变量
article_id=request.POST.get("article_id")
is_up=request.POST.get("is_up") #因为js默认post是urlencode,发送的是字符串,所以这里接收到的就是字符串
is_up=json.loads(is_up) #将收到的字符串通过json序列化为我们需要的布尔值
try:
with transaction.atomic(): #事务
obj=ArticleUpDown.objects.create(user_id=user_pk,article_id=article_id,is_up=is_up)
if is_up:
Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
else:
Article.objects.filter(pk=article_id).update(down_count=F("down_count") + 1)
except Exception as e:
res["state"]=False #变成踩灭状态
res["first_action"]=ArticleUpDown.objects.filter(user_id=user_pk,article_id=article_id).first().is_up #返回给ajax的数据多了first_action属性
return JsonResponse(res) #返回给ajax的时候,ajax不用反序列化,接收到的是一个字典格式
article_detail.html页面:
{% extends "base.html" %}
{% block content %}
<h3 class="text-center">{{ article_obj.title }}</h3>
<div class="article_content">
{{ article_obj.articledetail.content|safe }}
</div>
<div class="poll clearfix">
<div id="div_digg" class="clearfix">
<div class="diggit action">
<span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
</div>
<div class="buryit action">
<span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
</div>
<div class="clear"></div>
</div>
</div>
<div class="diggword" id="digg_tips" style="color: red;"></div>
<div class="info" article_id="{{ article_obj.pk }}" username="{{ request.user.username }}"></div> {#为了在静态文件article_detail.js中取到html页面的变量#}
{% csrf_token %}
<script src="/static/js/article_detail.js"></script>
{% endblock %}
因为我们的html是继承的base.html页面,所有要在base.html页面引入
<link rel="stylesheet" href="/static/css/article_detail.css">
article_detail.css样式代码:
#div_digg {
float: right;
margin-bottom: 10px;
margin-right: 30px;
font-size: 12px;
width: 125px;
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;
}
article_detail.js代码:
$(".action").click(function () { if ($(".info").attr("username")) { //表示当前用户登录 var is_up; is_up = $(this).hasClass("diggit"); article_id = $(".info").attr("article_id"); //根据属性查找取到article_detail.html页面article_id的值 // $.ajax({ url: "blog/digg/", type: "post", data: { is_up: is_up, article_id: article_id, csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val() //防止出现404 forbidden错误 }, success: function (data) { if (data.state) { // 点赞或者踩灭成功 if (is_up) { // 点赞成功 var val = $("#digg_count").text(); val = parseInt(val) + 1; $("#digg_count").text(val); } else { // 踩灭成功 var val = $("#bury_count").text(); val = parseInt(val) + 1; $("#bury_count").text(val); } } else { //重复提交 console.log(data.first_action); if (data.first_action) { $("#digg_tips").html("您已经推荐过了"); setTimeout(function () { // 1秒后下面的消息不显示 $("#digg_tips").html(""); }, 1000) } else { $("#digg_tips").html("您已经反对过了"); setTimeout(function () { $("#digg_tips").html(""); }, 1000) } } } }) } else{ //用户必须登录后才能进行点赞、踩灭 # var s="<a href='/login/' class='pull-right'>请登陆!</a>"; # $("#div_digg").after(s); //返回给用户“请登陆”信息 location.href = "/login/?next=" + location.pathname //直接调转到用户登录页面 } });
二、评论
1、js取标签里的值
select标签 .val();
input标签 .val();
textarea标签 .val();
div标签、span标签取里面值的时候用.html()或.text();
2、评论楼:
article_detail.html页面:
{% extends "base.html" %}
{% block content %}
<h3 class="text-center">{{ article_obj.title }}</h3>
<div class="article_content">
{{ article_obj.articledetail.content|safe }}
</div>
<ul class="comment_list list-group">
评论楼:
{% for comment in comment_list %}
<li class="comment_item list-group-item">
<div>
<a href="">#{{ forloop.counter }}</a>楼
<span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> {#显示时间,格式为年-月-日 时:分#}
<span>{{ comment.user.username }}</span> {#评论人,当前评论的评论名#}
<a class="pull-right reply_btn" username="{{ comment.user.username }}"
comment_id="{{ comment.pk }}"><span>回复</span></a>
</div>
{% if comment.parent_comment_id %} {#评论是子评论#}
<div class="parent_comment_infon well">
@{{ comment.parent_comment.user.username }} : {{ comment.parent_comment.content }}<br/>
{{ comment.content }}
</div>
{% else %} {#评论是根评论#}
<div class="comment_con">
<p>{{ comment.content }}</p>
</div>
{% endif %}
</li>
{% endfor %}
</ul>
<div class="comment">
<div>
昵称:
<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
value="{{ request.user.username }}">
</div>
<div>
<p>评论内容</p>
<textarea name="" id="comment_content" cols="115" rows="10"></textarea>
</div>
<button class="btn btn-default comment_btn">提交</button>
</div>
<div class="info" article_id="{{ article_obj.pk }}" username="{{ request.user.username }}"></div>
{% csrf_token %}
<script>
var pid = "";
$(".comment_btn").click(function () { // 提交评论事件
article_id = $(".info").attr("article_id"); //在页面根据属性查找得到当前文章id号
content = $("#comment_content").val(); //textarea标签通过.val()得到里面的值
// 处理文本框内容
if (pid) {
var index = content.indexOf("\n"); //得到\n换行符的索引
content = content.slice(index + 1) //换行符的索引加1的位置即我们所需要文本内容的开始位置
}
$.ajax({
url: "/blog/comment/",
type: "post",
data: {
article_id: article_id,
content: content,
pid: pid, //pid为空,则提交根评论
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
},
success: function (data) { //视图函数comment返回的数据
console.log(data);
ctime = data.ctime;
content = data.content;
username = $(".info").attr("username"); //从页面取到评论人的名字
s = '<li class="comment_item list-group-item temp"> <div> <span>' + ctime + '</span> <span>' + username + '</span> </div> <div class="comment_con"><p>' + content + '</p></div> </li>'
$(".comment_list").append(s);
$("#comment_content").val(""); //提交成功后,清空评论框里面的评论内容
pid = ""; //pid重新置空,这样接着在评论框里评论就变成了根评论,否则提交一直是子评论
}
})
});
$(".reply_btn").click(function () { // 回复按钮事件
$("#comment_content").focus(); // 获取输入框的焦点
var val = "@" + $(this).attr("username") + "\n";
$("#comment_content").val(val);
pid = $(this).attr("comment_id")
})
</script>
<script src="/static/js/article_detail.js"></script>
{% endblock %}
article_detail.css代码:
input.author {
background-image: url("/static/img/icon_form.gif");
background-repeat: no-repeat;
border: 1px solid #ccc;
padding: 4px 4px 4px 30px;
width: 300px;
font-size: 13px;
}
.comment_item .comment_con{
margin-top: 10px;
margin-left: 20px;
}
.conmment_item{
margin-left: 20px;
}
.comment {
width: 820px;
}
.parent_comment_infon{
position: relative;
margin: 0 40px 0 40px;
border: #ccc 1px dashed;
padding: 1px;
color: grey;
font-family: Arial,Helvetica,sans-serif;
font-size: 12px;
font-weight: normal;
text-decoration: none;
}
.comment_con{
position: relative;
margin: 0 10px 0 10px;
border: #ccc 1px dashed;
padding: 5px;
color: black;
font-family: Arial,Helvetica,sans-serif;
font-size: 15px;
font-weight: normal;
text-decoration: none;
}
.temp {
background-color: gainsboro;
}
views.py文件增加评论楼视图:
# 评论
def comment(request):
user_pk=request.user.pk
article_id=request.POST.get("article_id")
content=request.POST.get("content")
pid=request.POST.get("pid")
response={}
with transaction.atomic(): #事件
if not pid: # pid为空表示根评论
comment_obj=Comment.objects.create(user_id=user_pk,article_id=article_id,content=content) # 提交根评论
else: # 子评论
comment_obj = Comment.objects.create(user_id=user_pk, article_id=article_id, content=content,parent_comment_id=pid) # 提交子评论
Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)
response["ctime"]=comment_obj.create_time.strftime("%Y-%m-%d %H:%M") #返回给ajax的创建时间,时间格式为%Y-%m-%d %H:%M
response["content"]=comment_obj.content #返回给ajax的评论内容
return JsonResponse(response)
def article_detail(request,username,article_id):
user = UserInfo.objects.filter(username=username).first() # 查当前站点的用户对象
blog = user.blog
article_obj=Article.objects.filter(pk=article_id).first()
comment_list=Comment.objects.filter(article_id=article_id)
return render(request,"article_detail.html",locals())
3、评论树:
article_detail.html页面添加评论树代码:
<div class="comment_tree">
<p>评论树</p>
</div>
<script>
// 获取评论信息,以评论树形式展示
$.ajax({
url: "/blog/comment_tree/" + $(".info").attr("article_id"),
success: function (comment_list) {
console.log(comment_list);
html = "";
$.each(comment_list, function (index, comment_dict) {
var comment_pk=comment_dict["pk"]
var comment_content=comment_dict["content"]
temp= '<div comment_tree_id='+comment_pk+' class="conmment_item"> <span class="content">'+comment_content+'</span></div>'
if (!comment_dict.parent_comment_id) { // 没有父评论,即根评论
$(".comment_tree").append(temp)}
else { // 子评论处理
var pid=comment_dict.parent_comment_id;
$("[comment_tree_id="+pid+"]").append(temp)
}
});
}
});
</script>
views.py文件增加评论树视图函数:
def comment_tree(request,article_id):
comment_list=list(Comment.objects.filter(article_id=article_id).values("content","pk","parent_comment_id"))
print(comment_list)
return JsonResponse(comment_list,safe=False) #JsonResponse返回的是列表,需要参数safe=False处理
转载于:https://blog.51cto.com/qidian510/2122072