內容回顧
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中的三元運算:
還有就是事件委托