BBS - 文章評論

1、文章評論

 

    <div class="comment_region">
        <div class="row">
            <div class="col-md-8">
                <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
                <p>評論內容:</p>
                <textarea name="" id="comment-text" cols="63" rows="10"></textarea>
                <button class="btn btn-default pull-right comment-btn">提交</button>
            </div>
        </div>

    </div>

 

效果:javascript

 

事件:html

from django.db import transaction

def comment(request):
    article_id = request.POST.get('article_id')
    content =request.POST.get('content')
    pid = request.POST.get('pid')
    user_id = request.user.pk

    res = {"state":True}

    with transaction.atomic():   # 事務 有關聯
        if not pid: # 提交根評論
            obj = Comment.objects.create(user_id = user_id,article_id = article_id,content=content)
        else:  # 提交子評論
            obj = Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=pid)

        # comment_count 加 + 1
        Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)

    res['time'] = obj.create_time.strftime('%Y-%m-%d %H:%M')
    res['content'] = obj.content
    if obj.parent_comment_id:
        res['pid'] = obj.parent_comment_id
        res['pidname'] = obj.parent_comment.user.username
    return JsonResponse(res)


def get_comment_tree(request,article_id):
    ret = list(Comment.objects.filter(article_id=article_id).values('pk','content','parent_comment_id','user__username'))
    print(ret)
    return JsonResponse(ret,safe=False)
path('comment/', views.comment),
re_path(r'get_comment_tree/(\d+)', views.get_comment_tree),
comment_list = Comment.objects.filter(article_id=article_id)

 

評論樹  評論樓  提交評論事件:前端

{% extends 'base.html' %}

{% block content %}

    <h3 class="text-center">{{ article.title }}</h3>
    <div class="content">
        {{ article.articledetail.content|safe }}
    </div>


    <input type="hidden" id="hid_article_pk" value="{{ article.pk }}">
      <input type="hidden" id="hid_username" value="{{ request.user.username }}">

    <div id="div_digg">
        <div class="diggit digg">
            <span class="diggnum" id="digg_count">{{ article.up_count }}</span>
        </div>
        <div class="buryit digg">
            <span class="burynum" id="bury_count">{{ article.down_count }}</span>
        </div>
        <div id="digg_word" class="pull-right"></div>
    </div>
    <div class="clearfix"></div>

    <hr>
    <p>評論樹</p>
    <div class="comment_tree">

        <script>
            (function () {
                $.ajax({
                    url:'/blog/get_comment_tree/'+$('#hid_article_pk').val(),
                    success:function (comment_list) {

                        var comment_html = "";
                        $.each(comment_list,function (index,comment) {
                            var username = comment.user__username;
                            var content = comment.content;
                            var pk = comment.pk;
                            var pid = comment.parent_comment_id;
                            console.log(comment);
                             s = '<div class="comment_tree_item" id="'+pk+'"><span>'+username+'</span><span>'+content+'</span> </div>'

                             if(pid){
                                $('#'+pid).append(s)

                             }else{
                                 $('.comment_tree').append(s)
                             }
                        })
                    }
                })
            })()

        </script>

    </div>

    <hr>
    <p>評論樓</p>
    <ul class="list-group comment_list">
        {% for comment in comment_list %}
            <li class="list-group-item comment_item">
                <div>
                    <a href="">#{{ forloop.counter }}樓</a>&nbsp;&nbsp;&nbsp;
                    <span>{{ comment.create_time|date:'Y-m-d H:i'}}</span>&nbsp;&nbsp;
                    <a href="">{{ comment.user.username  }}</a>
                    <a class="pull-right replay" pk = "{{ comment.pk }}" username="{{ comment.user.username }}">回覆</a>
                </div>
                {% if comment.parent_comment_id %}
                    <div class="parent_comment_info well">
                        <a href="">@{{ comment.parent_comment.user.username }}</a>&nbsp;&nbsp;
                        <span>{{ comment.parent_comment.content }}</span>
                    </div>
                {% endif %}
                <div>
                    <p>{{ comment.content }}</p>
                </div>
            </li>
        {% endfor %}
    </ul>


    <hr>
    <div class="comment_region">
        <div class="row">
            <div class="col-md-8">
                <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
                <p>評論內容:</p>
                <textarea name="" id="comment-text" cols="63" rows="10"></textarea>
                <button class="btn btn-default pull-right comment-btn">提交</button>
            </div>
        </div>

    </div>


{% csrf_token %}

<script src="/static/js/article_detail.js"></script>

    <script type="text/javascript">

        var pid = '';  // 空 爲 根評論

        // 綁定 提交評論事件
        $('.comment-btn').click(function () {

            if("{{ request.user.username }}"){  // 登陸 後操做

                // val()   input select textarea 這三個能夠 取 val()
                var article_id = $('#hid_article_pk').val();

                if($('#comment-text').val()[0] !== "@"){
                    pid = ""
                }

                //@alex\n567
                // 獲取 子評論 內容
                if(pid){
                    var index = $('#comment-text').val().indexOf('\n');
                    var content = $('#comment-text').val().slice(index+1)
                }else{
                    var content = $('#comment-text').val();
                }

                $.ajax({
                    url:'/blog/comment/',
                    type:'post',
                    data:{
                        article_id:article_id,
                        content:content,
                        pid:pid,
                        csrfmiddlewaretoken:$('input[name="csrfmiddlewaretoken"]').val()
                    },
                    success:function (data) {
                        console.log(data);
                        if(data.state){  // 提交成功
                            console.log('-----------',data);
                            // 根評論 顯示
                            var floor = $('.comment_list .comment_item').length+1;
                            var ctime = data.time;
                            var username = $('#hid_username').val();
                            var content =  data.content;
                            var pname = data.pidname;
                            if(data.pid){  // 子評論
                                 var s ='<li class="list-group-item comment_item"><div><a href="">#'+floor+'樓</a>&nbsp;&nbsp;&nbsp; <span>'+ ctime+ ' </span>&nbsp;&nbsp;<a href="">'+ username +'</a> </div> <div> ' +
                                     ' <div class="parent_comment_info well">\n' +
                                     ' <a href="">@'+pname+'</a>&nbsp;&nbsp;\n' +
                                     ' </div>'+
                                     '<p>'+content+'</p> </div> </li>';
                            }else{
                                 // 應該有 2 套 s
                                 var s ='<li class="list-group-item comment_item"><div><a href="">#'+floor+'樓</a>&nbsp;&nbsp;&nbsp; <span>'+ ctime+ ' </span>&nbsp;&nbsp;<a href="">'+ username +'</a> </div> <div> <p>'+content+'</p> </div> </li>';
                            }

                            $('.comment_list').append(s);

                            //清空數據
                            $('#comment-text').val("");
                            //清空pid
                            pid = "";

                        }
                    }
                })

            }else{  // 未登陸
                location.href = "/login/"
            }
        });

        // 綁定回覆 按鈕事件
        $('.comment_item .replay').click(function () {
            // 獲取焦點
            $('#comment-text').focus();
            var val ="@" + $(this).attr('username')+ '\n';  // 回覆得人得 名字
            $('#comment-text').val(val);

            pid = $(this).attr("pk")  // pid
        })

    </script>


{% endblock content%}
article_detail.html

 

2、知識點

文章評論:
1.提交根評論
2.顯示根評論
--- render顯示
--- ajax顯示
3.提交子評論
4.顯示子評論
--- render顯示
--- ajax顯示
評論樓
評論樹

 

1.
comment_list = Comment.objects.filter(article_id=article_id)

2.事務
with transaction.atomic(): # 事務 數據統一 一致
if not pid: # 提交根評論
obj = Comment.objects.create(user_id = user_id,article_id = article_id,content=content)
else: # 提交子評論
obj = Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=pid)

# comment_count 加 + 1
Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)

3.a標籤
href = "url" 向外連接
href = '#xxx' 向內定位 錨點
不用#xxx,能夠用獲取焦點:$('#comment-text').focus();

4.val()
input select textarea 這三個能夠 取 .val() 賦值 .val('')

5.js得截取方法:(charAt indexOf slice)
var s = "hello world";
console.log(s.charAt(4)); // o 索引找字符
console.log(s.indexOf('e')); // 1 字符找索引
console.log(s.slice(1,4)); // ell 切片

6.根評論 / 子評論 獲取 content
var pid = ''; // 空 爲 根評論
if($('#comment-text').val()[0] !== "@"){
pid = ""
}

// 獲取 子評論 內容 // @alex\n567
if(pid){
var index = $('#comment-text').val().indexOf('\n');
var content = $('#comment-text').val().slice(index+1)
}else{
var content = $('#comment-text').val();
}

7.兩個bug:
(1) 先提交子評論,在不刷新頁面的狀況下再提交根評論會怎樣?
//清空數據
$('#comment-text').val("");
//清空pid
pid = "";
(2) 先按回覆按鈕,而後將文本框中的"@..."手動去除,再點提交會怎樣?
if($('#comment-text').val() !== "@"){
pid = ""
}

8.datatime.datetime
時間對象,不能序列化! 字典 列表 可序列化, 對象不可序列化!!
辦法:
res['time'] = obj.create_time.strftime('%Y-%m-%d %H:%M')
return JsonResponse(res)
補充:
import datetime
datetime.date
datetime.time
datetime.datetime
datetime.timedelta(days=7)

now = datetime.datetime.now() # 對象
now.strftime('%Y-%m')
now.strftime('%Y-%m-%d')
now.strftime('%Y-%m-%d %X')
now.strftime('%Y-%m-%d %H:%M')


delta = datetime.timedelta(days=7)
now + delta // 時間相加

9.評論樓
樓層:
<a href="">#{{ forloop.counter }}樓</a>&nbsp;
時間:
<span>{{ comment.create_time|date:'Y-m-d H:i'}}</span>&nbsp;
評論者:
<a href="">{{ comment.user.username }}</a>
回覆:(pk username)
<a class="pull-right replay" pk = "{{ comment.pk }}" username="{{ comment.user.username }}">回覆</a>
點擊回覆:
// 綁定回覆 按鈕事件
$('.comment_item .replay').click(function () {
// 獲取焦點
$('#comment-text').focus();
var val ="@" + $(this).attr('username')+ '\n'; // 回覆得人得 名字
$('#comment-text').val(val);

pid = $(this).attr("pk") // pid
})
判斷是否有父評論:
{% if comment.parent_comment_id %}
<div class="parent_comment_info well">
<a href="">@{{ comment.parent_comment.user.username }}</a>&nbsp;&nbsp;
<span>{{ comment.parent_comment.content }}</span>
</div>
{% endif %}

10.ajax顯示評論:
var floor = $('.comment_list .comment_item').length+1;
var ctime = data.time; // 時間字符串 由於時間對象json傳不過來。
var username = $('#hid_username').val();
var content = data.content; // content 應該從庫裏取,不該該直接拿前端得數據!由於前端得content是通過 過濾轉義 特殊字符後才存到數據庫中。
var pname = data.pidname;
if(data.pid){ // 子評論
var s ='<li class="list-group-item comment_item"><div><a href="">#'+floor+'樓</a>&nbsp;&nbsp;&nbsp; ' +
'<span>'+ ctime+ ' </span>&nbsp;&nbsp;<a href="">'+ username +'</a> </div> <div> ' +
' <div class="parent_comment_info well">\n' +
' <a href="">@'+pname+'</a>&nbsp;&nbsp;\n' +
' </div><p>'+content+'</p> </div> </li>';
}else{
// 應該有 2 套 s
var s ='<li class="list-group-item comment_item"><div><a href="">#'+floor+'樓</a>&nbsp;&nbsp;&nbsp;' +
' <span>'+ ctime+ ' </span>&nbsp;&nbsp;<a href="">'+ username +'</a> </div>' +
' <div> <p>'+content+'</p> </div> </li>';
}

$('.comment_list').append(s);

11.評論樹:
樣式:
111
444
555
222
333

方法:
1.遞歸!! 麻煩!
本身調本身
有個結束條件
2. comment_list 取出 pid
前端拿到,全部數據
先展現 全部得根評論
子評論 append到某條根評論下

<div pk=1>111
<div pk=4>444
<div pk=5>555</div>
</div>
</div>
<div pk=2>222</div>
<div pk=2>333</div>

知識點:
匿名函數,自執行!
(function () {
alert(111)
})()

應用: $.each(...)
<div class="comment_tree">
<script>
(function () {
$.ajax({
url:'/blog/get_comment_tree/'+$('#hid_article_pk').val(),
success:function (comment_list) {

var comment_html = "";
$.each(comment_list,function (index,comment) {
var username = comment.user__username;
var content = comment.content;
var pk = comment.pk;
var pid = comment.parent_comment_id;
console.log(comment);
var s = '<div class="comment_tree_item" id="'+pk+'"><span>'+username+'</span><span>'+content+'</span> </div>'

if(pid){ // 子評論
$('#'+pid).append(s)

}else{ // 父評論
$('.comment_tree').append(s)
}
})
}
})
})()

</script>
</div>

補充:
最新評論指定放到前面: (prepend)
jquery 文檔操做:
append appendTo
prepend prependTo
before insertBefore
after insertAfter
clone
replaceWith replaceAll
empty remove detach

樣式縮進:
.comment_tree_item{
margin-left: 20px;
}

後臺:
def get_comment_tree(request,article_id):
ret = list(Comment.objects.filter(article_id=article_id).values('pk','content','parent_comment_id','user__username'))
print(ret)
return JsonResponse(ret,safe=False)

注意點:
queryset 對象無法作 序列化
辦法:
list(quertset) # 強轉
BUT:
return JsonResponse(ret)
條件:
In order to allow non-dict objects to be serialized set the safe parameter to False.
修改:
return JsonResponse(ret,safe=False)
相關文章
相關標籤/搜索