你好,我是goldsunC
让我们一起进步吧!
两天没写Django了,没办法,这两天太忙了,发的文件处理和Scrapy也是稍微有点水,不过也还行,今天继续来一篇Django,不知道有人跟着做没有。
经过之前那么多篇的学习,相信如今再看某一部分的时候都知道它是干嘛的了,比如我们现在想实现一个功能:删除文章,首先应该怎么搞?谁来负责这个功能?当然是视图函数。
OK,先打开article/view.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请求删除文章")注意这个视图函数,当调用的时候首先要判断请求是否为POST,为什么这么做?那我们需要先普及一个东西:CSRF攻击。
CSRF攻击你可以理解为:攻击者盗用你的身份,以你的名义发送恶意请求。
比如:一个用户登录了我们的博客网站,浏览器现在往往会记录下这次会话,然后保持登录状态。如果用户没有退出登录,然后不小心打开了某个邪恶的网站,邪恶网站在页面中植入了恶意的代码,悄无声息的向我们的博客网站发送删除文章的请求,然后浏览器误以为用户在操作,就按照指令把文章删除了。
因为使用的同一个浏览器,CSRF攻击者并不需要知道你登录数据的实际内容,就可以欺骗浏览器,让恶意的请求附上正确的登录数据。假如你登录了某银行网站,忘记了退出登录,黑客就能悄悄地转走你所有的存款。
为了防范CSRF攻击,我们设定删除文章时只能用POST方法,并且同时校验csrf令牌。
CSRF令牌就是Django提交表单时附带的token,它如何防范CSRF攻击呢?
首先当用户访问Django站点时,Django反馈给用户的表单中有一个隐含字段token,这个值是在服务器随机生成的,每次都不一样。然后在后端处理POST请求前,Django会校验请求的cookie里的token和表单里的token是否一致。如果一致则请求合法,如果不一致则禁止访问。
因为攻击者不知道用户的cookie内容,所以往往无法知道正确的token,因此防范了此类攻击。
在默认情况下所有的POST请求都由Django中间件帮你验证了,因此视图函数限制请求为POST请求。
既然以及增加了视图函数,那往往下一步就是增加访问路由了,不然怎么执行函数呢?
打开article/urls,加入:
path('article-safe-delete/<int:id>/',views.article_safe_delete, name='article_safe_delete'),视图函数和访问路由都配置完毕了,那我们在网页的哪里调用呢?想了想还是先在文章详情页内放一个入口吧,因为毕竟我们删除文章前不得看看文章内容都是啥?当然,你也可以在任何地方增加入口,我们先在文章详情页来一个入口。
打开templates/article/detail.html,把删除文章按钮链接增加到作者名字之后(这里给出了detail.html的全部代码,稍后会讲解):
<!DOCTYPE html> <!-- extends表明此页面继承自 base.html 文件 --> {% extends "base.html" %} {% load staticfiles %} <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <!-- 写入 base.html 中定义的 title --> {% block title %} 文章详情 {% endblock title %} <body> <!-- 写入 base.html 中定义的 content --> {% block content %} <!-- 文章详情 --> <div class="container"> <div class="row"> <!-- 标题及作者 --> <h1 class="col-12 mt-4 mb-4">{{ article.title }}</h1> <div class="col-12 alert alert-success">作者:{{ article.author }} <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> </div> <!-- 文章正文 --> <div class="col-12"> <p>{{ article.body }}</p> </div> </div> </div> <script> // 删除文章的函数 function confirm_safe_delete() { // 调用layer弹窗组件 layer.open({ // 弹窗标题 title:"删除文章", // 正文 content:"确定要删除这篇文章吗?删了就没了!", // 点击确认按钮后调用的回调函数 yes:function (index, layero) { $('form#safe_delete button').click(); layer.close(index); } }) } </script> {% endblock content %} </body> </html>再打开templates/base.html:
<!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 --> <script src="{% static 'jquery/jquery-3.5.1.js' %}"></script> <script src="{% static 'layer/layer.js' %}"></script>上边包含了本篇内容的全部代码,分别更改了view.py、article/urls.py,detail.html、base.html四个文件。
不过你现在把所有代码更改了也不会正常运行,因为你少了个文件layer。
注意看base.html,前两行代码是之前文件中有的,最后一行是我们新加入的,这行代码就是导入layer文件,这个文件你得去下载,官网如下:
https://layer.layui.com/
下载之后是个压缩包,解压之后目录如下所示:
layer-v3.1.1 │ test.html │ 更新日志.txt │ ├─layer │ │ layer.js │ │ │ ├─mobile │ │ │ layer.js │ │ │ │ │ └─need │ │ layer.css │ │ │ └─theme │ └─default │ icon-ext.png │ icon.png │ layer.css │ loading-0.gif │ loading-1.gif │ loading-2.gif │ └─文档 jquery下载.url layer官网.url layer文档.url layui社区.url 获得layim.url我们需要的是其中的layer文件夹,把它复制,然后粘贴到项目文件夹的static目录下,完成之后目录应该是这样的:
static ├─bootstrap ├─jquery └─layerOK,如果你完成了这些操作,虽然可能还不知道我们都做了什么,但是网站应该能正确运行了,其中服务器,然后进入一个文章详情页,如下:
有了删除文章按钮,并且你按下之后会弹出一个窗口:
点击确认之后,就把文章删除了:
OK,大功告成,来我们说说都发生了什么。
首先是detail.html文件,它改的最多,也最重要。总的来看,首先它增加了一个删除文章的标签:
<a href="#" onclick="confirm_safe_delete()">删除文章</a>同时后面还紧跟了一个style="display:none;"隐藏的表单:
<form style="display:none;" id="safe_delete" action="{% url 'article:article_safe_delete' article.id %}" method="POST" > {% csrf_token %} <button type="submit">发送</button> </form>然后代码最后增加了一个JavaScript的函数:
<script> // 删除文章的函数 function confirm_safe_delete() { // 调用layer弹窗组件 layer.open({ // 弹窗标题 title:"删除文章", // 正文 content:"确定要删除这篇文章吗?删了就没了!", // 点击确认按钮后调用的回调函数 yes:function (index, layero) { $('form#safe_delete button').click(); layer.close(index); } }) } </script>首先看标签删除文章,该标签如果被点击了,那么就会调用我们这个JS的函数,那这个函数做了什么?首先调用了layer的组件,出现一个弹窗,弹窗标题和内容都是我们设定的,之后如果我们点击弹窗的确认,又会调用一个新的函数,这个函数干什么了?它调用了id=safe_delete的按钮表单,也就是我们加的那个隐藏的表单,那么那个表单干什么了?表单调用了article_safe_delete视图函数,发送的是POST请求。然后视图函数会开始操作。那么到这里,一个通路走完了,理解没?
参考文献:
https://www.dusaiphoto.com/article/2/http://c.biancheng.net/view/7288.htmlhttp://www.python3.vip/tut/webdev/django/