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中引用模板語言的變量,注意加引號!!!
                    html

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

咱們但願吧頁面佈局成這個樣式:ajax

在bootstrap找到樣式以後,做相應的改動:咱們先想一下,在這個區域須要哪些數據,首先就是評論發表的時間,評論的做者,還有評論的內容。因此在文章詳情頁面的試圖函數中應該傳一些comment的參數。以後再頁面中,經過for循環,逐個展現評論:sql

<!--評論展現區 開始-->
    <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代碼:django

<!--發表評論區 開始-->
    <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請求了。bootstrap

咱們可以很容易的寫出來這步:後端

//給評論按鈕綁定點擊事件 $('#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)

這樣基本的評論功能已經寫出來了,給文章評論以後,刷新以後在頁面上就可以展現出評論內容,app

可是咱們實際的評論不是這樣的,當咱們評論以後,評論內容就會立刻出如今展現區,不用經過刷新。這一步怎麼實現呢?函數

這就要求咱們在發送請求成功以後的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中的三元運算:

 還有就是事件委託

相關文章
相關標籤/搜索