根評論:對文章的評論;
子評論:對評論的評論;
區別:是否有父評論。
評論的流程:
1構建樣式
2提交根評論
3顯示根評論
--------render顯示
--------Ajax顯示
4提交子評論
5顯示子評論
--------render顯示
--------Ajax顯示
6評論樹的顯示
樓層結構:
111
222
333
樹形結構:(有父子關系,樓層的深度、層級)
111
222
444
555
333
1.評論樣式
article_detail.html
<div class="clearfix"> //評論和點贊在一行,這是由於點贊和反對做了一個浮動,而評論又在正常文檔中,導致它的浮動沒有清除;清除浮動在bootstrap里邊加個clearfix
<div id=“div_digg...”>
</div>
{# 評論樣式#} <div class="comments"> <p>發表評論</p> <p>昵稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p> <p>評論內容:</p> <textarea name="" id="comment_content" cols="60" rows="10"></textarea> //沒有必要放到form表單中,因為要Ajax提交;textarea為內聯標簽,給下面button加了個p標簽。 <p> <button class="btn btn-default commment_btn">提交評論</button> // </p> </div>
article_detail.css
input.author{ background-image: url("/static/font/icon_form.gif"); //引入圖標 background-repeat: no-repeat; border: 1px solid #ccc; padding: 4px 4px 4px 30px; width: 300px; font-size: 13px; background-position: 3px -3px; }
2.提交(保存)根評論
客戶端瀏覽器發 點贊或者評論按鈕給服務端,觸發一個事件(給它綁定一個click事件)發送請求,用戶一點擊就給服務器發請求了,有專門的視圖函數接收這個請求,提交評論信息交給comment視圖函數,視圖函數構建一個評論對象保存到數據庫里邊,然后再把響應交給回調函數(ajax發完請求給它個回調) ,通過響應結果來判斷如果對這個dom操作
views.py
#評論 def comment(request): print(request.POST) article_id = request.POST.get("article_id") #評論文章;user不用傳,create_time不用傳(評論的時間就是入庫的時間),評論表的字段。 pid = request.POST.get("pid") content = request.POST.get("content") #評論內容 user_id = request.user.pk #當前登錄人的id comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=pid) //pid是為空的,傳給父評論 return HttpResponse("comment")
article_detail.html
//評論請求 $(".commment_btn").click(function () { var pid = "" var content = $("#comment_content").val(); //找到這個標簽,val就是取里邊的內容 $.ajax({ url:"/comment/", type:"post", data:{ "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val(), "article_id":"{{ article_obj.pk }}", "content":content, "pid":pid //父評論的id,默認為空。根評論沒有 }, success: function (data) { //success回調函數 console.log(data) //清空評論框 $("#comment_content").val(""); } }) })
3.render顯示根評論(還有一種是Ajax)
views.py
def article_detail(request, username, article_id): ''' 文章詳情頁 :param request: :param username: :param article_id: :return: ''' user = models.UserInfo.objects.filter(username=username).first() #個人站點對象 blog = user.blog article_obj = models.Article.objects.filter(pk=article_id).first() #拿到文章對象,要傳到模板里邊去 # context = get_classification_data(username) comment_list = models.Comment.objects.filter(article_id=article_id) #拿出用戶訪問那篇文章的id return render(request, "article_detail.html", locals())
article_detail.html
<p>評論列表</p> <ul class="list-group comment_list"> {% for comment in comment_list %} //for循環這個comment_list <li class="list-group-item"> //每次循環生成一個 li標簽 <div> <a href="">#{{ forloop.counter }}樓</a> <span>{{ comment.create_time | date:"Y-m-d H:i" }}</span> <a href=""><span>{{ comment.user.username }}</span></a> <a href="" class="pull-right">回復</a> </div> <div class="comment_con"> <p>{{ comment.content }}</p> </div> </li> {% endfor %} </ul>
Ajax顯示評論
點提交按鈕,發Ajax請求;
Ajax請求在對應的視圖函數生成一個comment對象,然后我們響應給它的是comment對象相關的三個鍵值字典,字典返回給這個回調函數,拿到object對象構建一個標簽,把標簽字符串樣式放在了頁面的某個url里邊去了完成了dom操作。
success: function (data) { console.log(data); var create_time = data.create_time; //取出這三組變量,把這三個變量插入到下面反引號里邊,關於js必須用+不斷的去拼接,現在用ES6反引號的語句就很簡潔了 var username = data.username; var content = data.content; var s =` //反斜杠 ;構建一個標簽字符串像上邊那樣放到這個樣式里邊 ;通過dom操作放到這個url中 <li class="list-group-item"> <div> <span>${create_time}/span> //用反引號把字符串包起來,再用${}語法把它插入進來,js里邊的只能用+拼,ES6很像python的語法 <a href=""><span>${ username }</span></a> </div> <div class="comment_con"> <p>${content}</p> </div> </li> `; $("ul.comment_list").append(s);
views.py
#評論 def comment(request): print(request.POST) article_id = request.POST.get("article_id") pid = request.POST.get("pid") content = request.POST.get("content") user_id = request.user.pk comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=pid) response = {} #這個就是返回給回調函數的那個data。 response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X") response["username"] = request.user.username #當前評論人 response["content"] = content return JsonResponse(response) #返回一個字典,JsonResponse會幫我們做序列化操作; #return HttpResponse("comment")
先點提交按鈕發ajax請求,在對應的視圖函數中生成一個對象,響應給它的是comment相關信息-三個鍵值組成的字典,把字典返回給success回調函數,success拿到那個字典 拿到object對象,構建一個標簽,把標簽字符串放到頁面的某個ul里邊去了,完成一個dom操作。(在數據庫里邊生成一個comment記錄,同時在頁面上看到提交的這條評論信息了)
4. 回復按鈕事件
一點擊回復按鈕,就@這條評論的評論人; 定光標、賦文本值。
<div> <a href="">#{{ forloop.counter }}樓</a> <span>{{ comment.create_time | date:"Y-m-d H:i" }}</span> <a href=""><span>{{ comment.user.username }}</span></a> <a class="pull-right reply_btn" username= "{{ comment.user.username }}">回復</a> </div>
//回復按鈕事件 $(".reply_btn").click(function () { $('#comment_content').focus(); //聚焦 var val="@"+$(this).attr("username")+"\n"; //賦值,父評論的名字 $('#comment_content').val(val) })
5.提交子評論
<div> <a href="">#{{ forloop.counter }}樓</a> <span>{{ comment.create_time | date:"Y-m-d H:i" }} </span> <a href=""><span>{{ comment.user.username }}</span></a> <a class="pull-right reply_btn" username= "{{ comment.user.username }}" comment_pk="{{ comment.pk }}">回復</a> //給每個回復的按鈕多加一個自定義的屬性 </div>
//評論請求 var pid = ""; $(".commment_btn").click(function () { var content = $("#comment_content").val(); //把評論內容取出來 if(pid){ //判斷pid是否為空。 var index=content.indexOf("\n") content = content.slice(index+1) }
//清空評論框
pid = "", //加上它可以清除小bug(你不刷新時,不點擊回復按鈕之間輸入pid則為子評論)
$("#comment_content").val("");
//回復按鈕事件
$(".reply_btn").click(function () {
$('#comment_content').focus();
var val="@"+$(this).attr("username")+"\n";
$('#comment_content').val(val);
pid = $(this).attr("comment_pk")
})
6.Ajax顯示子評論
應該重新構建標簽字符串,從視圖中拿到父評論的相關信息,加到s字符串里邊
7.評論樹的顯示
權限展示成樹形結構,用遞歸
評論樹的請求數據
<div class="comments list-group"> <p class="tree_btn">評論樹</p> <div class="comment_tree"> {# <div class="comment_item" comment_id = "1">#} {# <span>111</span>#} {# <div class="comment_item" comment_id = "4">#} {# <span>444</span>#} {# <div class="comment_item" comment_id = "5">#} {# <span>555</span>#} {# </div>#} {# </div>#} {# </div>#} {# <div class="comment_item" comment_id = "2">#} {# <span>222</span>#} {# </div>#} {# <div class="comment_item" comment_id = "3">#} {# <span>333</span>#} {# </div>#} </div> <script> $(".tree_btn").click(function () { $.ajax({ url:"/get_comment_tree/", type:"get", data:{ data是views里return傳來的ret值 article_id : "{{ article_obj.pk }}" }, success:function(data){ console.log(data); $.each(data, function (index, comment_object) { var pk = comment_object.pk; var content = comment_object.content; var parent_comment_id = comment_object.parent_comment_id; var s = `<div class="comment_item" comment_id=` + pk + `><span>` + content + `</span></div>` if(!parent_comment_id){ $(".comment_tree").append(s); }else{ $("[comment_id = "+parent_comment_id+"]").append(s); } }) } }) }) </script>
views.py
def get_comment_tree(request): article_id = request.GET.get("article_id") ret = list(models.Comment.objects.filter(article_id=article_id).values("pk", "content", "parent_comment_id")) return JsonResponse(ret, safe=False)
根評論的序號一定大於子評論的序號
ret = list(models.Comment.objects.filter(article_id=article_id).order_by("pk").values("pk", "content", "parent_comment_id")) return JsonResponse(ret, safe=False)
<script> $.ajax({ url:"/get_comment_tree/", type:"get", data:{ article_id : "{{ article_obj.pk }}" }, success:function(comment_list){ console.log(comment_list); $.each(comment_list, function (index, comment_object) { var pk = comment_object.pk; var content = comment_object.content; var parent_comment_id = comment_object.parent_comment_id; var s = `<div class="comment_item" comment_id=` + pk + `><span>` + content + `</span></div>` if(!parent_comment_id){ $(".comment_tree").append(s); }else{ $("[comment_id = "+parent_comment_id+"]").append(s); } }) } }); {# $(".tree_btn").click(function () {#} {# $.ajax({#} 把ajax放在外邊,就不用點擊了才能看到評論數了。 {# url:"/get_comment_tree/",#} {# type:"get",#} {# data:{#} {# article_id : "{{ article_obj.pk }}"#} {# },#} {# success:function(comment_list){#} {# console.log(comment_list);#} {# $.each(comment_list, function (index, comment_object) {#} {# var pk = comment_object.pk;#} {# var content = comment_object.content;#} {# var parent_comment_id = comment_object.parent_comment_id;#} {# var s = `<div class="comment_item" comment_id=` + pk + `><span>` + content + `</span></div>`#} {##} {# if(!parent_comment_id){#} {# $(".comment_tree").append(s);#} {# }else{#} {# $("[comment_id = "+parent_comment_id+"]").append(s);#} {# }#} {# })#} {# }#} {# })#} {# })#} </script>
評論事務操作
from django.db import transaction
#事務操作 with transaction.atomic(): comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=pid) models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)
評論的郵件發送
EMAIL_HOST = 'smtp.exmail.qq.com' #如果是163改成 smtp.163.com
EMAIL_POST = 465
EMAIL_HOST_USER = ' ' #賬號
EMAIL_HOST_PASSWORD = ' ' #密碼
#DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USE_SSL = True