既然有了寫文章的功能,那固然也必需要有刪除文章的功能了。html
有了以前的學習作鋪墊,刪除文章實現起來就比較簡單了。前端
首先增長一個視圖函數:python
article/views.py ... # 刪文章 def article_delete(request, id): # 根據 id 獲取須要刪除的文章 article = ArticlePost.objects.get(id=id) # 調用.delete()方法刪除文章 article.delete() # 完成刪除後返回文章列表 return redirect("article:article_list")
id
;.delete()
函數刪除數據庫中這篇文章的條目;這裏與上一章同樣,不對用戶的身份進行限制,即任何人均可以刪除任意文章。固然這樣確定是不符合常理的,等到咱們學習了用戶管理的知識後,再回頭來修改。jquery
而後寫入路由信息:git
article/urls.py ... urlpatterns = [ ... # 刪除文章 path('article-delete/<int:id>/', views.article_delete, name='article_delete'), ]
這裏幾乎與文章詳情的寫法同樣,沒有新的內容。再次注意文章的id是如何傳遞到視圖中的。github
最後咱們但願可以在文章詳情的頁面進行刪除的操做(固然也能夠在專門的管理文章的頁面中),所以修改模板detail.html
:web
templates/article/detail.html ... <!-- 文章詳情 --> <div class="container"> <div class="row"> ... <div class="col-12 alert alert-success">做者:{{ article.author }} · <a href="{% url "article:article_delete" article.id %}">刪除文章</a> </div> ... </div> </div> ...
這裏增長了一個調用article_delete
視圖函數的連接,而且將article.id
傳遞進去。數據庫
運行開發服務器,能夠發現已經可以正常的刪除文章了:django
功能已經實現了,可是還有個小問題沒有解決:萬一我只是不當心點到了連接,辛辛苦苦寫的文章就被刪除了,豈不是欲哭無淚了?bootstrap
很容易想到的一個解決方法,就是點擊刪除按鈕是出現一個彈窗,確認後再進行刪除,確保用戶不是誤操做的。
彈窗是很經常使用的功能,可是想寫出一個美觀好用的彈窗卻不容易。幸運的是咱們不須要重複造輪子,早就有革命先驅作好相關的功能了,這裏咱們選擇使用Layer彈窗組件。
layer是一款備受青睞的web彈層組件,具有全方位的解決方案。首先到官網下載Layer插件:Layer
解壓後將裏面的layer文件夾(含有layer.js的)直接複製到項目的static
文件夾下。
爲了將來在全部頁面都能使用Layer彈窗功能,在base.html
中經過標籤引入:
templates/base.html ... <body> ... <!-- bootstrap.js 依賴 jquery.js 和popper.js,所以在這裏引入 --> <script src="{% static 'jquery/jquery-3.3.1.js' %}"></script> ... <!-- 引入layer.js --> <script src="{% static 'layer/layer.js' %}"></script> </body> ...
layer插件依賴jquery才能正常工做,所以要在jquery的後面引入layer。
再次改寫模板文件detail.html
:
templates/article/detail.html ... <!-- 文章詳情 --> <div class="container"> <div class="row"> ... <div class="col-12 alert alert-success">做者:{{ article.author }} · <a href="#" onclick="confirm_delete()">刪除文章</a> </div> ... </div> </div> <script> // 刪除文章的函數 function confirm_delete() { // 調用layer彈窗組件 layer.open({ // 彈窗標題 title: "確認刪除", // 正文 content: "確認刪除這篇文章嗎?", // 點擊肯定按鈕後調用的回調函數 yes: function(index, layero) { // 指定應當前往的 url location.href='{% url "article:article_delete" article.id %}' }, }) } </script> {% endblock content %}
<a>
標籤中增長了onclick
屬性,表示在點擊連接時調用後面的confirm_delete()
函數。confirm_delete()
函數中調用了layer彈窗組件,對彈窗的標題、正文以及肯定鍵進行了定義。location.href
是點擊肯定鍵後應該前往的地址,即刪除文章的url。(固然Layer組件遠不止這些用法,具體可在官方文檔中查閱)。onclick
實現了功能邏輯,所以href
連接就不須要再跳轉了。不要將模板語法和JavaScript語法搞混了。包裹在 {% .. %} 中的是Django的模板語法。Django在模板語法幫助下將零散的模板文件拼接成完整的html文件,再傳遞到用戶的瀏覽器中進行解析。模板語法適合執行一些簡單的邏輯。
包裹在
script
標籤中的是JavaScript語法,它是與Python不一樣的、可以在瀏覽器中運行的前端語言。學好JavaScript一樣是一個漫長的過程,好在本教程中只會涉及一點基本的JavaScript代碼。
保存全部文件後刷新頁面,很好,達到了理想的效果:
可能你認爲刪除文章功能實現起來沒什麼難度,可是請注意,上面的方法是有隱患的。要繼續深刻探討,就得提到跨域請求僞造攻擊,也稱爲CSRF攻擊了(Cross-site request forgery)。
CSRF攻擊你能夠理解爲:攻擊者盜用了你的身份,以你的名義發送惡意請求。仍是拿刪除文章舉例:
因爲瀏覽器的同源策略,CSRF攻擊者並不能獲得你的登陸數據實際內容,可是能夠欺騙瀏覽器,讓惡意請求附上正確的登陸數據。不要小看CSRF攻擊的威力:假若是你的銀行帳戶具備此類安全漏洞,黑客就能夠神不知鬼不覺轉走你的全部存款。
因此這裏如何防範CSRF攻擊的風險呢?方法是有的,即刪除文章時用POST方法,而且校驗csrf
令牌。
前面咱們講到在 Django 中提交表單必須加csrf_token
,這個就是CSRF令牌了,它防範CSRF攻擊的流程以下:
csrf_token
,這個值是在服務器端隨機生成的,每次都不同;csrf_token
和表單裏的 csrf_token
是否一致。一致則請求合法,不然這個請求多是來自於 CSRF攻擊,返回 403 服務器禁止訪問。因爲攻擊者並不能獲得用戶的 cookie 內容(僅僅是靠瀏覽器轉發),因此一般狀況下是沒法構造出正確的 csrf_token
的,從而防範了此類攻擊。原理就是這樣,下面來看看如何實現安全的刪除功能。
首先修改刪除文章的連接,以及點擊它時調用的函數:
templates/article/detail.html ... <!-- · <a href="#" onclick="confirm_delete()">刪除文章</a> --> · <a href="#" onclick="confirm_safe_delete()">刪除文章</a> <!-- 新增一個隱藏的表單 --> <form style="display:none;" id="safe_delete" action="{% url 'article:article_safe_delete' article.id %}" method="POST" > {% csrf_token %} <button type="submit">發送</button> </form> ... <script> ... function confirm_safe_delete() { layer.open({ title: "確認刪除", content: "確認刪除這篇文章嗎?", yes: function(index, layero) { $('form#safe_delete button').click(); layer.close(index); } }) } </script>
代碼流程以下:
接着添加表單提交的url:
article/urls.py ... urlpatterns = [ ... # 安全刪除文章 path( 'article-safe-delete/<int:id>/', views.article_safe_delete, name='article_safe_delete' ), ]
最後就是將新的刪除視圖寫好:
article/views.py ... # 安全刪除文章 def article_safe_delete(request, id): if request.method == 'POST': article = ArticlePost.objects.get(id=id) article.delete() return redirect("article:article_list") else: return HttpResponse("僅容許post請求")
可能你要問了,沒發現哪行代碼校驗了csrf
令牌啊?放心,默認配置下全部的 POST 請求都由 Django 中間件幫你驗證了。另外視圖必定要限制爲 POST 請求,即if request.method == 'POST'
必須有,就請讀者思考一下緣由吧。
本章新增了刪除博客文章的功能,而且使用了彈窗組件優化了用戶體驗。
另外一個重要的知識點就是CSRF攻擊的防範。記住一條,凡是重要的數據操做,都應該考慮帶有 csrf 令牌的 POST 請求;或者更簡單的方法,數據查詢用 GET,數據更改用 POST。
注意這個刪除文章的功能並無對用戶身份進行驗證。別急,等到講完用戶管理以後再來處理。
下一章將學習如何更新文章,準備好繼續做戰吧。