由于做博客园系统的时候发现评论功能的实现耗费蛮长时间,比较适合练习,遂整理如下:
评论分为:对文章的评论和对评论的评论。
有两种方式实现多级评论,一种类似博客园特色的评论方式,盖楼@某位用户。一种采用树形结构实现,涉及一个很重要的点:字典和列表是引用数据类型,或者说可变类型;字典的键必须是不可变类型(可以是整型)。
主要整理第二种,学习数据结构的设计思想:
评论结构:
数字代表评论的ID号,由一张专门的comment表存放。
1,2,3,9为根级评论,代表对文章的评论,其余为子评论,代表对父级评论的评论。
class Comment(models.Model): ''' 一篇文章可以有多个评论,一条评论只能属于一篇文章; 一个用户可以有多条评论,一条评论只能属于一个用户; 评论还可以有评论; 还有一个字段存放用户评论时间; 评论点赞次数; ''' commentInfo=models.CharField(max_length= 200,verbose_name= "评论内容") article=models.ForeignKey("Article",verbose_name= "评论文章") user=models.ForeignKey("UserInfo",verbose_name= "评论人") parent_id=models.ForeignKey("self",verbose_name= "父级评论",null=True) #做了修改 create_time=models.DateTimeField(verbose_name= "评论时间",auto_now_add= True) # 设置评论被赞的次数 up_count=models.IntegerField(default= 0) def __str__(self): return self.commentInfo # 通过评论找文章:(正向)article_obj=comment_obj.article # 通过文章找评论:(反向)article_obj.comment_set.all # 通过评论找到评论用户:(正向)comment_obj.user
代码实现:
方式一:
方式二:
推荐方式二:尽量避免for循环嵌套for循环方式,优化性能。
评论功能实现要点记录:
第一点:点击评论可以直接定位到评论输入框,技术实现:锚点或者前端的scrollIntoView()用法。
第二点:评论区采用富文本编辑框Kindeditor。注意上传文件以及路径配置。详细参考官网文档:http://kindeditor.net/doc.php
主要代码截取:
#############views.py#############
def upload_file(request):
if request.method == "POST":
file_obj = request.FILES.get("imgFile")
print(file_obj, type(file_obj)) # 1.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
print(file_obj.name, type(file_obj.name)) # 1.jpg <class 'str'>
file_name = file_obj.name
file_path = os.path.join("blog/media/upload/img/", file_name) # blog/media/upload/img/1.jpg
print(file_path)
with open(file_path, "wb") as f:
for chunk in file_obj.chunks():
f.write(chunk)
response_put = {
"error": 0,
"url": "/media/upload/img/" + file_name, # 特别注意路径问题
}
return HttpResponse(json.dumps(response_put))
##################templates之articledetail.html################## <form> {% csrf_token %} <h5>评论:</h5> <div id="contentArea2"> <textarea cols="60" rows="10" id="contentArea"> {# 试了,name不可以 #} </textarea> </div> <div> <input type="button" value="提交" class="CommentSub"> </div> </form> {# 富文本编辑框设置#} Keditor = KindEditor.create("#contentArea", { width: "850px", resizeType: 1, uploadJson: "/upload_file/", {# 指定上传文件的服务器端程序。 #} extraFileUploadParams: {"csrfmiddlewaretoken": "{{ csrf_token }}"}, {# 上传图片、Flash、视音频、文件时,支持添加别的参数一并传到服务器。 #} filePostName: "imgFile" });
非常有用的取值和赋值操作:
第三点:采用文本编辑框输入评论内容,用ajax方式提交评论时,要注意运用:$(document).ready(function(){})============>$(function(){})
第四点:处理新添评论时,前端有两种方式,一种字符串拼接,还有我们可以有效的借助别人写好的格式化字符串处理工具。
第五点:BeautifulSoup模块 --针对标签进行匹配查询
第六点:文章一载入即显示树形评论
##############递归函数############## {# 递归函数#} function makeCommentTree(comment_list) { var htmls = ''; $.each(comment_list, function (i, comment) { {# console.log(i, comment);#} {# var comment_str = '<div class="comment_item"><div class="content"><span>' + comment["id"] + '</span></div>';#} var comment_str = '<div class="comment_item"><div class="row">' + '<div class="col-md-1"><a href="#"><img src="' + comment["comment_user_headPic"] + '" width="40px" height="40px" class="comment_user_headPic"></a></div>' + '<div class="col-md-11"><span class="comment_time">' + comment["create_time"] + '</span>' + '<a href="#" class="comment_user">' + comment["comment_user_username"] + '</a>' + '<a href="#contentArea2" class="comment_comment pull-right">回复<span class="glyphicon glyphicon-comment"></span></a>' + '<a href="#" class="pull-right">支持<span class="glyphicon glyphicon-thumbs-up"></span> </a>' + '<div class="comment_info">' + comment["commentInfo"] + '</div><span class="' + comment["id"] + '"></span></div></div>'; if (comment["children_comments"]) { comment_str += makeCommentTree(comment["children_comments"]); } comment_str += '</div>'; htmls += comment_str; }); return htmls; }
################样式设置:多级评论显示出层级效果的关键一步: $(".comment_item").css({"marginLeft": "40px", "marginBottom": "10px"});
tips1:无序字典变有序字典
from collections import OrderDict import collections comment_dict=collections.OrderDict()
tips2:常用
1、window.location.href(设置或获取整个 URL 为字符串) var test = window.location.href; alert(test); 返回:http://i.cnblogs.com/EditPosts.aspx?opt=1 2、window.location.protocol(设置或获取 URL 的协议部分) var test = window.location.protocol; alert(test); 返回:http: 3、window.location.host(设置或获取 URL 的主机部分) var test = window.location.host; alert(test); 返回:i.cnblogs.com 4、window.location.port(设置或获取与 URL 关联的端口号码) var test = window.location.port; alert(test); 返回:空字符(如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符) 5、window.location.pathname(设置或获取与 URL 的路径部分(就是文件地址)) var test = window.location.pathname; alert(test); 返回:/EditPosts.aspx 6、window.location.search(设置或获取 href 属性中跟在问号后面的部分) var test = window.location.search; alert(test); 返回:?opt=1 PS:获得查询(参数)部分,除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值。 7、window.location.hash(设置或获取 href 属性中在井号“#”后面的分段) var test = window.location.hash; alert(test); 返回:空字符(因为url中没有) 8、js获取url中的参数值
暂时就这些。
当然博客系统还有很多未整理出来的,比如用户注册时上传头像的预览,涉及的FormData。验证码的刷新。对文章按日期归档时运用的自定义管理器。
request.path运用(
要求:
1 用户登陆后才能访问某些页面,
2 如果用户没有登录就访问该页面的话直接跳到登录页面
3 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址)
后续补充。