django框架之BBS項目之評論功能


內容回顧
    1. BBS項目 CMS
        1. 登錄
            1. form組件
            2. auth模塊
            3. 驗證碼
        2. 注冊
            1. form組件
                1. 生成html代碼
                    直接for循環form_obj,就能夠遍歷所有字段
                2. 驗證
                    1. 默認的那些驗證
                    2. 正則的驗證
                    3. 全局鈎子做確認密碼的驗證
                    4. 判斷用戶名是否已經存在
                        1. input框失去焦點就發ajax到后端判斷
                        2. form組件中使用局部鈎子來判斷    
                    
            2. auth模塊 --> 擴展auth_user表 --> create_user()
                1. UserInfo這個類里面,avatar是一個FileField
                    avatar = models.FileField(upload_to="avatars/", default="avatars/default.png")
                2. 注意事項:
                    1. FileField保存的是一個路徑,而不是一個文件
                    2. upload_to:具體保存的文件路徑就會在media目錄下
            3. 上傳頭像
                1. ajax如何上傳文件
                2. Django中media的配置
                    1. settings.py中:
                        - MEDIA_URL:別名
                        - MEDIA_ROOT:給用戶上傳的所有文件指定一個存放目錄
                    2. urls.py中:
                        from django.views.static import serve
                        from django.conf import settings
                        
                        url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT})
        3. 博客首頁
            1. 文章列表(排樣式)
            2. 分頁
                1. 封裝的要徹底
                2. 封裝后的結果要有普適性(url要寫成配置項)
        4. 個人博客主頁
            1. 分類
                1. 文章分類
                2. 文章標簽
            2. 日期歸檔
                1. 日期格式化函數    --> MySQL內置的函數都有哪一些?      --> 《漫畫數據庫》
                    1. MySQL:DATE_FORMAT('字段', '格式')
                    2. sqlite:strftime('格式', '字段')
                
                2. ORM中如何執行原生的SQL語句
                    1. 使用extra()在執行ORM查詢的同時,嵌入一些SQL語句
                    2. 直接執行原生SQL語句
                        from django.db import connection
                        cursor = connection.cursor()
                        cursor.execute('select id from userinfo;')
                        cursor.fetchall()    
                3. 分組聚合
                    QuertySet.annotate()  --> 分組,前面查的是什么字段就按什么字段分組        
                    QuertySet.aggregate() --> 聚合,給QuerySet中的每個對象多一個屬性
                    
                4. 4合1路由
                    不同的路由可以使用同一個視圖函數!!! --> 視圖函數中通過參數的不同,實現不同的功能
        5. 文章詳情頁
            1. 母板繼承
            2. inclusion_tag
                1. 返回一段HTML代碼,用數據填充的HTML代碼
                2. 具體的寫法
                    1. 在app下面創建一個名為 templatetags 的 Python Package
                    2. 在上面的包中創建一個 py文件
                    3. 按照inclusion_tag的格式要求寫功能函數
                        
                        from django import template
                        register = template.Library()
                        
                        @register.inclusion_tag(file='xx.html')
                        def show_menu(*arg):
                            ...
                            return {"k1": "v1"}
                            (xx.html中使用k1這個變量)    
            3. 點贊
                1. ajax發送點贊的請求
                    1. 點贊必須是登錄用戶,沒登錄跳轉到登錄頁面
                    2. 不能給自己的文章點贊
                    3. 一個用戶只能給一篇文章點一次贊或踩一次
                
                2. 后端創建點贊記錄(事務操作)
                    1. 創建新的點贊記錄
                    2. 去對應的文章表里把點贊數更新一個
                3. ORM事務操作
                    from django.db import transaction
                    
                    with transaction.atomic():
                        sql1;
                        sql2;
                        
                4. Django模板語言里面的JS代碼
                    如何在js中引用模板語言的變量,注意加引號!!!
                   

接下來就開始寫評論區的功能了,首先就是在頁面布局:

我們希望吧頁面布局成這個樣式:

在bootstrap找到樣式之后,作相應的改動:我們先想一下,在這個區域需要哪些數據,首先就是評論發表的時間,評論的作者,還有評論的內容。所以在文章詳情頁面的試圖函數中應該傳一些comment的參數。之后再頁面中,通過for循環,逐個展示評論:

<!--評論展示區 開始-->
    <h4>評論</h4>
    <div class="list-group comment-list">
        {% for comment in comment_list %}
            <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#{{ forloop.counter }}樓</span>
                    <span>{{ comment.create_time|date:'Y-m-d H:i' }}</span>
                    <span>{{ comment.user.username }}</span>
                    <span></span>
                </h4>
                <p class="list-group-item-text">{{ comment.content }}</p>
            </div>
        {% endfor %}
    </div>
    <!--評論展示區 結束-->

接下來就是發表評論的區域了:

同樣是先布局,然后html代碼:

<!--發表評論區 開始-->
    <h4>發表評論</h4>
    <div>昵稱:
        <input type="text"value="{{ request.user.username }}" disabled>
    </div>
    <div>
        <p>評論內容:</p>
        <textarea cols="60" rows="10"></textarea>
    </div>
    <div>
        <button class="btn btn-success">提交</button>
    </div>
    <!--發表評論區 結束-->

接下來就是發送ajax請求了。

我們能夠很容易的寫出來這步:

 //給評論按鈕綁定點擊事件
    $('#submit-comment').click(function () {
        var userid = '{{ request.user.id }}';
        var articleid = '{{ article_obj.id }}';
        var content = $('#new-comment').val();
        var csrf_token = $('[name="csrfmiddlewaretoken"]').val();
        $.ajax({
            url:'/comment/',
            type:'post',
            data:{
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
            }
        })
    })
試圖函數也可以這樣寫;

def
comment(request): if request.method == 'POST': res = {'code':0} user_id = request.POST.get('user_id') article_id = request.POST.get('article_id') content = request.POST.get('content')
    
with transaction.atomic():
     # 1.先去創建新評論
comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)
     # 2.再去更新該文章的評論數
models.Article.objects.update(comment_count=F('comment_count')+1)
   return JsonResponse(res)

這樣基本的評論功能已經寫出來了,給文章評論之后,刷新之后在頁面上就能夠展示出評論內容,

但是我們實際的評論不是這樣的,當我們評論之后,評論內容就會馬上出現在展示區,不用通過刷新。這一步怎么實現呢?

這就要求我們在發送請求成功之后的success函數中將它通過js操作展示出來,說白了就是在原來評論展示區的下面再添加一個展示區。所以試圖函數要返回一些數據:

views.py代碼:

def comment(request):
    if request.method == 'POST':
        res = {'code':0}
        user_id = request.POST.get('user_id')
        article_id = request.POST.get('article_id')
        content = request.POST.get('content')     
    
with transaction.atomic():
     # 1.先去創建新評論
comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)
     # 2.再去更新該文章的評論數
models.Article.objects.update(comment_count=F('comment_count')+1)
    res['data'] = { 
      'id':comment_obj.id,
      'username':comment_obj.user.username,
      'content':comment_obj.content,
      'create_time':comment_obj.create_time.strftime("Y-m-d") # 這部如果看不懂的話就去復習一下那三種時間格式的相互轉化 }

    return JsonResponse(res)

在說js操作代碼之前,我們先來復習一個知識:就是js中的字符串格式化輸出。

 # 給評論按鈕綁定點擊事件
$('#submit-comment').click(function () { var userid = '{{ request.user.id }}'; var articleid = '{{ article_obj.id }}'; var content = $('#new-comment').val(); var csrf_token = $('[name="csrfmiddlewaretoken"]').val(); $.ajax({ url:'/comment/', type:'post', data:{ user_id:userid, article_id:articleid, content:content, csrfmiddlewaretoken:csrf_token, }, success:function (res) { console.log(res) if(res.code===0){ var data = res.data //先計算原來.comment-list的后代有幾個div,即有幾個人評論,然后再加一 var num = $('.comment-list>div').length + 1; //創建評論成功后,通過js在評論區列表在添加一條評論 var commenthtml = ` <div href="#" class="list-group-item"> <h4 class="list-group-item-heading comment-header"> <span>#${ num }樓</span> <span>${ data.create_time }</span> <span>${ data.username }</span> <span></span> </h4> <p class="list-group-item-text">${ data.content }</p> </div> ` //在原來的評論列表后面添加一條 $('.comment-list').append(commenthtml) //情空 textarea $('#new-comment').val('') } } }) })

上面寫的是添加父評論。

接下來添加子評論,就是回復的部分了:

博客園中當我們點擊回復按鈕時,評論區會顯示這樣:

分為兩部:當我們點擊回復標簽時,光標就會聚焦在評論區,並且出現了@xxx

這個如何實現呢?

$('.replay').click(function () {
        //光標聚焦在textarea
        //出現@xxx
        var replayname = $(this).prev().text() //取到當前標簽的前一個標簽的文本
        $('#new-comment').focus().val('@'+replayname+'\n')
    })

comment表里有parent_comment字段,我們應該怎么取到這個字段的id呢?

當我們點擊提交的時候,我們不管有沒有父評論都給后端傳一個parent_id,我們給評論的那個div加一個自定義的id    

<div href="#" class="list-group-item" my_id="{{ comment.id }}">
<!--評論展示區 開始-->
    <h4>評論</h4>
    <div class="list-group comment-list">
        {% for comment in comment_list %}
            <div href="#" class="list-group-item" my_id="{{ comment.id }}">
                <h4 class="list-group-item-heading comment-header">
                    <span>#{{ forloop.counter }}樓</span>
                    <span>{{ comment.create_time|date:'Y-m-d H:i' }}</span>
                    <span>{{ comment.user.username }}</span>
                    <span></span>
                </h4>
          {% if comment.parent_comment %}
                        <span style="display: block">@{{ comment.parent_comment.user.username }}</span>
                        <p class="list-group-item-text well">
                            {{ comment.parent_comment.content }}
                        </p>
                  {% endif %} <p class="list-group-item-text">{{ comment.content }}</p> </div> {% endfor %} </div> <!--評論展示區 結束-->

那么我們如何區分誰是父評論誰是子評論呢?當我們點擊回復的時候,產生的評論就是子評論,直接點擊提交就是父評論,那我們應該怎么操作呢?

我們把這個自定義的id添加到提交的按鈕上,當我們點擊提交的按鈕是進行判斷,如果這個id存在,就說明是子評論,否則就是父評論。

  //點擊回復按鈕時的綁定事件
$('.replay').click(function () { //光標聚焦在textarea //出現@xxx var replayname = $(this).prev().text() ;//取到當前標簽的前一個標簽的文本 $('#new-comment').focus().val('@'+replayname+'\n'); //把當前評論的id值,存到提交的按鈕中 var pID = $(this).parent().parent().attr('my-id'); $('#submit-comment').data('pid',pID) })
 //給評論按鈕綁定點擊事件
    $('#submit-comment').click(function () {
        var userid = '{{ request.user.id }}';
        var articleid = '{{ article_obj.id }}';
        var content = $('#new-comment').val();
        var csrf_token = $('[name="csrfmiddlewaretoken"]').val();
        var parentId = $(this).data('pid') || '';
        if(parentId){
        //因為在添加自評論時,會出現@xxx的東西所以我們按照索引把他去除 content
= content.slice(content.indexOf('\n')+1,); } $.ajax({ url:'/comment/', type:'post', data:{ parent_id:parentId, user_id:userid, article_id:articleid, content:content, csrfmiddlewaretoken:csrf_token, }, success:function (res) { console.log(res) if(res.code===0){ var data = res.data //先計算原來.comment-list的后代有幾個div,即有幾個人評論,然后再加一 var num = $('.comment-list>div').length + 1; //創建評論成功后,通過js在評論區列表在添加一條評論 var commenthtml = ` <div href="#" class="list-group-item"> <h4 class="list-group-item-heading comment-header"> <span>#${ num }樓</span> <span>${ data.create_time }</span> <span>${ data.username }</span> <span></span> </h4> <p class="list-group-item-text">${ data.content }</p> </div> `; //在原來的評論列表后面添加一條 $('.comment-list').append(commenthtml); //情空 textarea $('#new-comment').val('');
            //當我們點擊提交按鈕時,應該把自定義的id去掉,不然下一次點擊提交的時候,還是有這個id值 $(
"#submit-comment").removeData("pid"); } } }) });

我們后端也能拿到parent_id。

def comment(request):
    if request.method == 'POST':
        res = {'code':0}
        user_id = request.POST.get('user_id')
        article_id = request.POST.get('article_id')
        content = request.POST.get('content')
        parent_id = request.POST.get("parent_id")
        #創建評論
        with transaction.atomic():
            # 1.先去創建新評論
            if parent_id:
                #添加自評論
                comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=parent_id)
            else:
                #添加父評論
                comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)
            # 2.再去更新該文章的評論數
            models.Article.objects.update(comment_count=F('comment_count')+1)
        res['data'] = {
            'parent_id':parent_id,
            'id':comment_obj.id,
            'username':comment_obj.user.username,
            'content':comment_obj.content,
            'create_time':comment_obj.create_time.strftime("Y-m-d")
        }
        return JsonResponse(res)

 這樣添加的評論還不夠完美,就是添加的評論沒有回復這個功能,  

 //給評論按鈕綁定點擊事件
    $('#submit-comment').click(function () {
        var userid = '{{ request.user.id }}';
        var articleid = '{{ article_obj.id }}';
        var content = $('#new-comment').val();
        var csrf_token = $('[name="csrfmiddlewaretoken"]').val();
        var parentId = $(this).data('pid') || '';
        if(parentId){
            //因為在添加自評論時,會出現@xxx的東西所以我們按照索引把他去除
            content = content.slice(content.indexOf('\n')+1,);
        }
        $.ajax({
            url:'/comment/',
            type:'post',
            data:{
                parent_id:parentId,
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
                if(res.code===0){
                    var data = res.data
                    //先計算原來.comment-list的后代有幾個div,即有幾個人評論,然后再加一
                    var num = $('.comment-list>div').length + 1;
                    //創建評論成功后,通過js在評論區列表在添加一條評論
                    var commenthtml = `
                    <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#${ num }樓</span>
                    <span>${ data.create_time }</span>
                    <span>${ data.username }</span>
                    <span class="pull-right replay">回復</span>
                </h4>
                    <p class="list-group-item-text">${ data.content }</p>
                </div>
                    `;
                    //在原來的評論列表后面添加一條
                    $('.comment-list').append(commenthtml);
                    //情空 textarea
                    $('#new-comment').val('');
                    //當我們點擊提交按鈕時,應該把自定義的id去掉,不然下一次點擊提交的時候,還是有這個id值
                    $("#submit-comment").removeData("pid");
                }
            }
        })
    });

添加回復這個按鈕后,不能實現點擊,這就用到了事件委托,當一個事件不能完成時,我們把它委托給他的父標簽做將來的動作。

    //給回復按鈕綁定事件
    //$('.replay').click(function () {
    //事件委托,
     $('.comment-list').on('click','.replay',function () {
        //光標聚焦在textarea
        //出現@xxx
        var replayname = $(this).prev().text() ;//取到當前標簽的前一個標簽的文本
        $('#new-comment').focus().val('@'+replayname+'\n');
        //把當前評論的id值,存到提交的按鈕中
        var pID = $(this).parent().parent().attr('my-id');
        $('#submit-comment').data('pid',pID)
    })

這就是完整的代碼了

不懂得地方看視頻,(看視頻day79. 004)

上面設計到的知識點,jquery中的data方法,就是我們可以給任意一個jQuery對象添加一個值。

js中的三元運算:

 還有就是事件委托

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM