既然有了写文章的功能,那固然也必需要有删除文章的功能了。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。
注意这个删除文章的功能并无对用户身份进行验证。别急,等到讲完用户管理以后再来处理。
下一章将学习如何更新文章,准备好继续做战吧。