评论的显示
1.数据库设计:(创建一个评论表)
class Comments(Base):
"""
"""
content = models.TextField(verbose_name="内容", help_text="内容")
author = models.ForeignKey('user.Users', on_delete=models.SET_NULL, null=True)
news = models.ForeignKey('News', on_delete=models.CASCADE)
pareent=models.ForeignKey('self',on_delete=models.CASCADE,null=True,blank=True)#关联父级关联
class Meta:
ordering = ['-update_time', '-id']
db_table = "tb_comments" # 指明数据库表名
verbose_name = "评论" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
def __str__(self):
return '<评论{}>'.format(self.id)
#将数据序列化输出
def to_dict(self):
comm_dict={
'news_id':self.news_id,
'content_id':self.id,
'content':self.content,
'update_tiem':self.update_time.strftime('%Y年%m月%d日 %H:%M'),
'author':self.author.username ,
'pareent':self.pareent.to_dict() if self.pareent else None,
}
return comm_dict;
2.在视图函数中写相应的代码,因为评论和新闻详情在一块,所以评论应该放在新闻详情这一块中
class New_detail(View):
def get(self,request,news_id):
#获取数据
new= News.objects.select_related('tag', 'author').only('title', 'content', 'update_time', 'tag__name',
'author__username').filter(delete_is=False, id=news_id).first()
#获取数据
comments=Comments.objects.select_related('author','pareent').only('author__username','update_time','content',
'pareent__update_time').filter(delete_is=False,id=news_id)
comment_list=[];
for c in comments:
comment_list.append(c.to_dict())
if new:
# return render(request,'news/news_detail.html',context={'news':new})
return render(request,'news/news_detail.html',locals())
else:
return HttpResponseNotFound('<h1>页面不存在</h1>')
前端页面的书写:
{% extends 'base/base.html' %}
{% block title %}文章详情页{% endblock %}
{% block link %}
<link rel="stylesheet" href="../../static/css/news/news-detail.css">
{% endblock %}
{% block main_contain %}
<div class="main-contain">
<div class="news-contain">
<h1 class="news-title">{{ new.title }}</h1>
<div class="news-info">
<div class="news-info-left">
<span class="news-author">{{ new.author.username }}</span>
<span class="news-pub-time">{{ new.update_time }}</span>
<span class="news-type">{{ new.tag.name }}</span>
</div>
</div>
<article class="news-content">
{{ new.content | safe}}
</article>
<div class="comment-contain">
<div class="comment-pub clearfix">
<div class="new-comment">
文章评论(<span class="comment-count">0</span>)
</div>
{% if user.is_authenticated %}
<div class="comment-control logged-comment" news-id="{{ news.id }}">
<input type="text" placeholder="请填写评论">
<button class="comment-btn">发表评论</button>
</div>
{% else %}
<div class="comment-control please-login-comment" news-id="{{ news.id }}">
<input type="text" placeholder="请登录后参加评论" readonly>
<button class="comment-btn">发表评论</button>
</div>
{% endif %}
</div>
<ul class="comment-list">
{% for one_comment in comment_list %}
<li class="comment-item">
<div class="comment-info clearfix">
<img src="{% static 'images/avatar.jpeg' %}" alt="avatar" class="comment-avatar">
<span class="comment-user">{{ one_comment.author }}</span>
<!--<span class="comment-pub-time">{{ one_comment.update_time }}</span>-->
</div>
<div class="comment-content">{{ one_comment.content }}</div>
{% if one_comment.pareent %}
<div class="parent_comment_text">
<div class="parent_username">{{ one_comment.pareent.author }}</div>
<br/>
<div class="parent_content_text">
{{ one_comment.pareent.content }}
</div>
</div>
{% endif %}
<div class="comment_time left_float">{{ one_comment.update_time }}</div>
<a href="javascript:void(0);" class="reply_a_tag right_float">回复</a>
<form class="reply_form left_float" comment-id="{{ one_comment.content_id }}"
news-id="{{ one_comment.news_id }}">
<textarea class="reply_input"></textarea>
<input type="button" value="回复" class="reply_btn right_float">
<input type="reset" name="" value="取消" class="reply_cancel right_float">
</form>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}
{% block script %}
{% endblock %}
评论追加
1.js编写(难点)
$(function () {
// 未登录提示框
let $loginComment = $('.please-login-comment input');
let $send_comment = $('.logged-comment .comment-btn');
$('.comment-list').delegate('a,input', 'click', function () {
let sClassValue = $(this).prop('class');
if (sClassValue.indexOf('reply_a_tag') >= 0) {
$(this).next().toggle();
}
if (sClassValue.indexOf('reply_cancel') >= 0) {
$(this).parent().toggle();
}
if (sClassValue.indexOf('reply_btn') >= 0) {
// 获取新闻id、评论id、评论内容
let $this = $(this);
let news_id = $this.parent().attr('news-id');
let parent_id = $this.parent().attr('comment-id');
let content = $this.prev().val();
if (!content) {
message.showError('请输入评论内容!');
return
}
// 定义发给后端的参数
let sDataParams = {
"content": content,
"pareent_id": parent_id
};
$.ajax({
url: "/news/"+news_id+"/comments/",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(sDataParams),
dataType: "json",
})
.done(function (res) {
if (res.errno === "0") {
let one_comment = res.data;
let html_comment = ``;
html_comment += `
<li class="comment-item">
<div class="comment-info clearfix">
<img src="/static/images/avatar.jpeg" alt="avatar" class="comment-avatar">
<span class="comment-user">${one_comment.author}</span>
</div>
<div class="comment-content">${one_comment.content}</div>
<div class="parent_comment_text">
<div class="parent_username">${one_comment.parent.author}</div>
<br/>
<div class="parent_content_text">
${one_comment.parent.content}
</div>
</div>
<div class="comment_time left_float">${one_comment.update_time}</div>
<a href="javascript:;" class="reply_a_tag right_float">回复</a>
<form class="reply_form left_float" comment-id="${one_comment.content_id}" news-id="${one_comment.news_id}">
<textarea class="reply_input"></textarea>
<input type="button" value="回复" class="reply_btn right_float">
<input type="reset" name="" value="取消" class="reply_cancel right_float">
</form>
</li>`;
$(".comment-list").prepend(html_comment);
$this.prev().val(''); // 请空输入框
$this.parent().hide(); // 关闭评论框
} else if (res.errno === "4101") {
// 用户未登录
message.showError(res.errmsg);
setTimeout(function () {
// 重定向到打开登录页面
window.location.href = "/user/login/";
}, 800)
} else {
// 失败,打印错误信息
message.showError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
}
});
// 点击评论框,重定向到用户登录页面
$loginComment.click(function () {
$.ajax({
url: "/news/" + $(".please-login-comment").attr('news-id') + "/comments/",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
})
.done(function (res) {
if (res.errno === "4101") {
message.showError("请登录之后再评论!");
setTimeout(function () {
// 重定向到打开登录页面
window.location.href = "/user/login/";
}, 800)
} else {
// 失败,打印错误信息
message.showError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// 发表评论
$send_comment.click(function () {
// 获取新闻id、评论id、评论内容
let $this = $(this);
let news_id = $this.parent().attr('news-id');
// let parent_id = $this.parent().attr('comment-id');
let content = $this.prev().val();
if (!content) {
message.showError('请输入评论内容!');
return
}
// 定义发给后端的参数
let sDataParams = {
"content": content
};
$.ajax({
url: "/news/"+news_id+"/comments/",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(sDataParams),
dataType: "json",
})
.done(function (res) {
if (res.errno === "0") {
let one_comment = res.data;
let html_comment = ``;
html_comment += `
<li class="comment-item">
<div class="comment-info clearfix">
<img src="/static/images/avatar.jpeg" alt="avatar" class="comment-avatar">
<span class="comment-user">${one_comment.author}</span>
</div>
<div class="comment-content">${one_comment.content}</div>
<div class="comment_time left_float">${one_comment.update_time}</div>
<a href="javascript:;" class="reply_a_tag right_float">回复</a>
<form class="reply_form left_float" comment-id="${one_comment.content_id}" news-id="${one_comment.news_id}">
<textarea class="reply_input"></textarea>
<input type="button" value="回复" class="reply_btn right_float">
<input type="reset" name="" value="取消" class="reply_cancel right_float">
</form>
</li>`;
$(".comment-list").prepend(html_comment);
$this.prev().val(''); // 请空输入框
// $this.parent().hide(); // 关闭评论框
} else if (res.errno === "4101") {
// 用户未登录
message.showError(res.errmsg);
setTimeout(function () {
// 重定向到打开登录页面
window.location.href = "/user/login/";
}, 800)
} else {
// 失败,打印错误信息
message.showError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// get cookie using jQuery
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// Setting the token on the AJAX request
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
});
相应的视图函数编写:
class CommentView(View):
def post(self,request,news_id):
if not request.user.is_authenticated:#判断是否有用户登录
return to_json_data(errno=Code.SESSIONERR,errmsg="用户没有登录,请登录再评论")
if not News.objects.only('id').filter(delete_is=False,id=news_id).exists():#判断是否有相应的新闻
return to_json_data(errno=Code.PARAMERR, errmsg='新闻不存在!')
#获取参数
json_data=request.body;#获取前端传过来的参数
if not json_data:
return to_json_data(errno=Code.PARAMERR, errmsg='传输的值有误!')
dict_data=json.loads(json_data);#j将闯过来的字符串类型的数据转换成字典类型
content=dict_data.get('content');#获取输入的评论内容
if not content:
return to_json_data(errno=Code.PARAMERR, errmsg='评论内容不能为空!')
# 回复评论 --- 二级评论
parent_id = dict_data.get('pareent_id')
try:
if parent_id:
if not Comments.objects.only('id').filter(is_delete=False, id=parent_id, news_id=news_id).exists():
return to_json_data(errno=Code.PARAMERR, errmsg='评论内容不能为空!');
except Exception as e:
logging.info('前台传的parent_id 异常:\n{}'.format(e))
return to_json_data(errno=Code.PARAMERR, errmsg='未知异常')
# 保存数据库
news_content = Comments()
news_content.content = content
news_content.news_id = news_id
news_content.author = request.user
news_content.pareent_id = parent_id if parent_id else None
news_content.save()
return to_json_data(data=news_content.to_dict())