Django搭建个人博客:编写删除文章功能

4945阅读 · 53评论 · 2018/10/08发布   前往评论

既然有了写文章的功能,那当然也必须要有删除文章的功能了。

不安全的方式

有了之前的学习做铺垫,删除文章实现起来就比较简单了。

首先增加一个视图函数:

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()函数删除数据库中这篇文章的条目;
  • 删除成功后返回到文章列表。

这里与上一章一样,不对用户的身份进行限制,即任何人都可以删除任意文章。当然这样肯定是不符合常理的,等到我们学习了用户管理的知识后,再回头来修改。

然后写入路由信息:

article/urls.py

...

urlpatterns = [
    ...
    # 删除文章
    path('article-delete/<int:id>/', views.article_delete, name='article_delete'),
]

这里几乎与文章详情的写法一样,没有新的内容。再次注意文章的id是如何传递到视图中的。

最后我们希望能够在文章详情的页面进行删除的操作(当然也可以在专门的管理文章的页面中),因此修改模板detail.html

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传递进去。

运行开发服务器,可以发现已经能够正常的删除文章了:

增加弹窗

功能已经实现了,但是还有个小问题没有解决:万一我只是不小心点到了链接,辛辛苦苦写的文章就被删除了,岂不是欲哭无泪了?

很容易想到的一个解决方法,就是点击删除按钮是出现一个弹窗,确认后再进行删除,确保用户不是误操作的。

弹窗是很常用的功能,但是想写出一个美观好用的弹窗却不容易。幸运的是我们不需要重复造轮子,早就有革命先驱做好相关的功能了,这里我们选择使用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攻击你可以理解为:攻击者盗用了你的身份,以你的名义发送恶意请求。还是拿删除文章举例:

  • 用户登录了博客网站A,浏览器记录下这次会话,并保持了登录状态;
  • 用户在没有退出登录的情况下,又非常不小心的打开了邪恶的攻击网站B
  • 攻击网站B在页面中植入恶意代码,悄无声息的向博客网站A发送删除文章的请求,此时浏览器误以为是用户在操作,从而顺利的执行了删除操作。

由于浏览器的同源策略,CSRF攻击者并不能得到你的登录数据实际内容,但是可以欺骗浏览器,让恶意请求附上正确的登录数据。不要小看CSRF攻击的威力:倘若是你的银行账户具有此类安全漏洞,黑客就可以神不知鬼不觉转走你的所有存款。

所以这里如何防范CSRF攻击的风险呢?方法是有的,即删除文章时用POST方法,并且校验csrf令牌。

CSRF令牌

前面我们讲到在 Django 中提交表单必须加csrf_token,这个就是CSRF令牌了,它防范CSRF攻击的流程如下:

  • 当用户访问 django 站点时,django 反馈给用户的表单中有一个隐含字段 csrf_token,这个值是在服务器端随机生成的,每次都不一样;
  • 在后端处理 POST 请求前,django 会校验请求的 cookie 里的 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>

代码流程如下:

  • 点击删除文章链接时,弹出 layer 弹窗
  • 弹窗不再发起 GET 请求,而是通过 Jquery 选择器找到隐藏的表单,并点击发送按钮
  • 表单发起 POST 请求,并携带了 csrf 令牌,从而避免了 csrf 攻击

接着添加表单提交的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。

注意这个删除文章的功能并没有对用户身份进行验证。别急,等到讲完用户管理之后再来处理。

下一章将学习如何更新文章,准备好继续作战吧。




本文作者: 杜赛
发布时间: 2018年10月08日 - 19:37
最后更新: 2019年09月03日 - 22:26
知识共享许可协议   转载请保留原文链接及作者


登录 后回复

共有53条评论

avatar
Superb来了 么么哒! 5

javascript:if(confirm('确认删除这篇文章吗?'))location='{% url 'blog:delete' post_id=post.id %}'

这样也可以,就是样式丑了点儿...

10个月前 回复


avatar
杜赛 [博主] Superb来了 么么哒! 4

不错,直接就在标签中调用了

10个月前 回复


avatar
Python 么么哒! 4

你好!我又是来求助的:实现弹窗功能,JS代码和教程一样,但是总是加载不了?点击“删除文章”没一点反应。

<script>
    // 删除文章的函数
    function confirm_delete() {
        // 调用layer弹窗组件
        layer.open({
            // 弹窗标题
            title: "确认删除",
            // 正文
            content: "确认删除这篇文章吗?",
            // 点击确定按钮后调用的回调函数
            yes: function(index, layero) {
                // 指定应当前往的 url
                location.href='{% url "article:article_delete" article.id %}'
            },
        })
    }
</script>
<!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 -->
<script src="{% static 'jquery/jquery-3.3.1.js' %}"></script>
<script src="{% static 'popper/popper-1.14.4.js' %}"></script>
<!-- 引入bootstrap的js文件 -->
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<!-- 引入layer.js -->
<script src="{% static 'layer/layer.js' %}"></script>

 

9个月前 回复


avatar
杜赛 [博主] Python 么么哒! 4

JS文件正常载入了吗?JS函数的名称写对了吗?

你打开浏览器的控制台(Chrome浏览器中按Ctrl + Shift + I,然后点击 Console 窗口),再点击删除按钮,控制台中有没有提示什么错误?

9个月前 回复


avatar
Python 杜赛 [博主] 么么哒! 4

按你的方法提示如下(本人初学者,不好意思):

Uncaught TypeError: layer.open is not a function                (index):67
    at confirm_delete ((index):67)
    at HTMLAnchorElement.onclick (VM39 :53)

该载入的都载入了,之前bootstrap都可以正常加载,没有设置弹出框之前也可以正常删除文章。

9个月前 回复


avatar
杜赛 [博主] Python 么么哒! 5

提示中说 layer.open 不是一个函数,可能是 layer.js 没能够正确加载。

你再跟着教程相关部分,重新引入 layer.js 试试。

细心一些,不要有拼写错误。

或者新建一个html页面专门测试弹窗功能。

也可以参考我的GitHub仓库中的示例代码,对比看和你的代码有哪里不一样。

要还不行就把你的项目打包发到我Email,我明后天有空了帮你排错。

9个月前 回复


avatar
Python 杜赛 [博主] 么么哒! 4

谢谢,我先试试,不行再发你邮箱。之前我发现不了错误,直接到教程拷贝了代码,直接覆盖了。还是不行。而且有个怪现象一直以来命令提示符,都出现JQ.js(404 1690)和popper.js (404  1693)报错,但是又不影响功能。不知道是不是和这个弹窗相关。

9个月前 回复


avatar
杜赛 [博主] Python 么么哒! 4

嗯嗯,感觉是js导入时出了问题。

你再找找bug,折腾也是技术进步的一大动力哦laugh

实在不行就发我邮箱。

9个月前 回复


avatar
Python 杜赛 [博主] 么么哒! 4

实在不行了,今天找了半天了,找各种技术教程的办法都尝试了。已发您邮箱,受累!

9个月前 回复


avatar
杜赛 [博主] Python 么么哒! 5

收到您的邮件了。

争取明天给你回复wink你可以先看看后面的章节

9个月前 回复


avatar
杜赛 [博主] Python 么么哒! 4

我看过你的项目了。错误原因很简单:

你没有安装Jquery和Popper这两个JS文件!

没有这两个文件,你的Bootstrap某些功能也是运行不起来的,只不过还没用到而已。

安装完成后弹窗功能就能正常使用了。

两个小建议:

1. 善于阅读报错提示。浏览器控制台报错 jquery 404 not found,应该顺藤摸瓜检查相关文件的正确性。

2. 写程序一定不要粗心。改写模板文件这个章节讲解了如何安装这两个静态文件。粗心会导致很多莫名其妙的bug。

希望可以帮到你。smiley

9个月前 回复


avatar
Python 杜赛 [博主] 么么哒! 4

是的。我就总感觉怎么JQ和Popper总是报错404.原来是我将这两个文件夹放到了bootstrap下了,应该是与它平级的。感谢!!

9个月前 回复


avatar
zpz 杜赛 [博主] 么么哒! 3
本回复已被 zpz 删除

7个月前 回复


avatar
zpz 杜赛 [博主] 么么哒! 4

···(index):67 Uncaught TypeError: layer.open is not a function
    at confirm_delete ((index):67)
    at HTMLAnchorElement.onclick (VM507 :54)···

博主您好,我也遇到了这个问题,但是我检查了,jquery和popper都安装引用了,不知道问题粗在哪里?

7个月前 回复


avatar
杜赛 [博主] zpz 么么哒! 4

layer.js引入正确了吗?

还有layer.js要在jquery.js的后面引入哦

7个月前 回复


avatar
zpz 杜赛 [博主] 么么哒! 4

好像是我下载的layer文件有错,换成了你的就好了,谢谢博主解答

7个月前 回复


avatar
pidada Python 么么哒! 4
本回复已被 pidada 删除

6个月前 回复


avatar
pidada Python 么么哒! 4

你这个JavaScript的代码放错位置了吧?应该放在detail.html 中的吧?  你放在base.html中了

6个月前 回复


avatar
CearlERO zpz 么么哒! 4
本回复已被 CearlERO 删除

4个月前 回复


avatar
Yami0425 么么哒! 3

答主您好~我的上面三种错误存在每一个页面,最后一个错误是在点击删除文章的时候才有的。我按照上面两位提问者的方法都试了一遍都不行

1、Uncaught SyntaxError: Invalid regular expression: missing /

2、Uncaught TypeError: Cannot read property 'fn' of undefined util.js:56
    at util.js:56
    at util.js:10
    at bootstrap.min.js:6
    at bootstrap.min.js:6
(anonymous) @ util.js:56
(anonymous) @ util.js:10
(anonymous) @ bootstrap.min.js:6
(anonymous) @ bootstrap.min.js:6
layer.js:2

3、Uncaught TypeError: i is not a function
    at Object.o.run (layer.js:2)
    at layer.js:2
    at layer.js:2
    at layer.js:2
o.run @ layer.js:2
(anonymous) @ layer.js:2
(anonymous) @ layer.js:2
(anonymous) @ layer.js:2
4、(index):74 Uncaught TypeError: layer.open is not a function
    at confirm_delete ((index):74)
    at HTMLAnchorElement.onclick ((index):61)

还有我观察pycharm运行提示中,只有这一行的状态码是404,

"GET /static/popper/popper.js.map HTTP/1.1" 404 1684

但是我的popper都是从您给的链接里下载的,本来想从您的github复制一下,发现没有这个文件

 

麻烦答主帮我解答一下~~谢谢

7个月前 回复


avatar
Yami0425 Yami0425 么么哒! 4

没事了答主,我把所有文件更新了一遍之后重启ide就好了  

顺便想说,我一个月前开始看网站开发,见过很多教程,这个很友好了!!真的是棒极了

7个月前 回复


avatar
杜赛 [博主] Yami0425 么么哒! 4

刚下班看到你的留言。

不用客气,对你的学习有帮助就好~

7个月前 回复


avatar
starinsun 么么哒! 4

博主你好,我在添加删除弹窗时出现了错误:

Uncaught ReferenceError: confirm_delete is not defined
    at HTMLAnchorElement.onclick (VM418 :53)
onclick @ VM418 :53

不知道能否指引一下这时哪儿出错了,static文件夹是直接拷贝您的,开发环境有区别于您,是python3.6加django2.2,使用的wsl开发的。

6个月前 回复


avatar
杜赛 [博主] starinsun 么么哒! 4

没有找到confirm_delete这个函数。

仔细检查一下是不是有拼写错误或者语法错误

6个月前 回复


avatar
pidada 么么哒! 3

 博主  你好!我加了删除函数之后,重新在后台增加了1篇文章,然后进不到这篇文章的详情页面,报错如下;

我发现好像就是加入layer插件和jQuery后才有的。

我之前建立的文章详情页面还是正常进入的

DoesNotExist at /article/article_detail/8/

ArticlePost matching query does not exist.
Request Method:GETRequest URL:http://127.0.0.1:8000/article/article_detail/8/Django Version:2.1Exception Type:DoesNotExistException Value:

ArticlePost matching query does not exist.
Exception Location:C:\Users\admin\blog\lib\site-packages\django\db\models\query.py in get, line 399Python Executable:C:\Users\admin\blog\Scripts\python.exePython Version:3.7.2Python Path:

['D:\\djangoStudying\\Git_Repos\\django_env\\django_projects\\blog',
 'D:\\Python\\python37.zip',
 'D:\\Python\\DLLs',
 'D:\\Python\\lib',
 'D:\\Python',
 'C:\\Users\\admin\\blog',
 'C:\\Users\\admin\\blog\\lib\\site-packages',
 'C:\\Users\\admin\\blog\\lib\\site-packages\\setuptools-39.1.0-py3.7.egg']

 

6个月前 回复


avatar
杜赛 [博主] pidada 么么哒! 4

跟layer和jquery没有关系。

你这个是没有找到对应 id 的文章。看一下这篇文章还在不在,或者视图里的逻辑是不是有点问题。

6个月前 回复


avatar
ac1864 么么哒! 4

哎,勉强通过copy做出了页面。

先走完全部的流程,然后再看第二遍。

感谢作者的教程,让我这个django菜鸟能坚持下来。

下定决心学习django好久了,总卡在前端。

这次也卡在前端,但是通过copy paste 过关了。

谢谢。

5个月前 回复


avatar
innocence_caosm 么么哒! 3

删除功能点击无法使用检查出来是这样的提示,不知道怎么解决,希望老师能指点一下,谢谢!

GET http://127.0.0.1:8000/static/jquery/jquery-3.3.1.js net::ERR_ABORTED 404 (Not Found)
(index):96 GET http://127.0.0.1:8000/static/popper/popper-1.14.4.js net::ERR_ABORTED 404 (Not Found)
util.js:56 Uncaught TypeError: Cannot read property 'fn' of undefined
    at util.js:56
    at util.js:10
    at bootstrap.min.js:6
    at bootstrap.min.js:6
(anonymous) @ util.js:56
(anonymous) @ util.js:10
(anonymous) @ bootstrap.min.js:6
(anonymous) @ bootstrap.min.js:6
(index):100 GET http://127.0.0.1:8000/static/layer/layer.js net::ERR_ABORTED 404 (Not Found)

3个月前 回复


avatar
杜赛 [博主] innocence_caosm 么么哒! 3

你这个原因是所有的静态文件都没加载上。好好检查一下。

3个月前 回复


avatar
liuchangfu 么么哒! 3

博主,您好,文章删除和修改这里,不是自己创建的文章,也可以修改和删除文章,如果要处理这个问题,要在那里加入判断逻辑,是在视图层处理,还是在模板处理?没有思路,请指点下,谢谢。。

2个月前 回复


avatar
杜赛 [博主] liuchangfu 么么哒! 3

在视图里处理。

用 request.user 取得当前登录用户,用 article.author 取得文章作者。对比一下两个的 id 就知道是不是同一个人了,是的话就允许修改,不是就返回错误提示页面。

这章没讲这个是因为还没有涉及到用户登录。后面有讲的。

2个月前 回复


avatar
zigzag 么么哒! 2

博主您好,首先很感谢您的个人博客给我带来了很大的帮助。

我在复现您的代码时在弹窗警告这里出现了控制台里出现了layer.open is not a function的错误,应该怎么解决呢?

这里是detail.html部分

<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_delete()">删除文章</a>
        </div>
        <!-- 博客正文用markdown渲染 -->
        <div class="col-12">
            <p>{{ article.body|safe }}</p>
        </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>

这里是base.html部分

<body>
    <!-- 引入导航栏 -->
    {% include 'header.html' %}
    <!-- 预留具体页面的位置 -->
    {% block content %}{% endblock content %}
    <!-- 引入注脚 -->
    {% include 'footer.html' %}
    <!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 -->
    <script src="{% static 'jquery/jquery.js' %}"></script>
    <script src="{% static 'popper/popper.js' %}"></script>
    <!-- 引入bootstrap的js文件 -->
    <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
    <!-- 引入layer.js 依赖jquery -->
    <script src="{% static 'layer/layer.js' %}"></script>
</body>

希望能得到您的帮助

2个月前 回复


avatar
zigzag zigzag 么么哒! 3
本回复已被 zigzag 删除

2个月前 回复


avatar
杜赛 [博主] zigzag 么么哒! 2

layer.js 没有正确载入吧。你打开网页源码,点击引入 layer.js 的标签,看能正确显示文件内容不

2个月前 回复


avatar
zigzag 杜赛 [博主] 么么哒! 3

我把base中

<body>
    <!-- 引入导航栏 -->
    {% include 'header.html' %}
    <!-- 预留具体页面的位置 -->
    {% block content %}{% endblock content %}
    <!-- 引入注脚 -->
    {% include 'footer.html' %}
    <!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 -->
    <script src="{% static 'jquery/jquery.js' %}"></script>
    <script src="{% static 'popper/popper.js' %}"></script>
    <!-- 引入bootstrap的js文件 -->
    <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
    <!-- 引入layer.js 依赖jquery -->
    <script src="{% static 'layer/layer.js' %}"></script>
</body>

这部分内容写在layer前面就可以实现了,但是放在后面就不行,不知道怎么回事。

2个月前 回复


avatar
杜赛 [博主] zigzag 么么哒! 3

html 页面是顺序向下执行的,所以静态文件要先载入,才能取到里面的内容。这个问题可以用模板语法 block 来解决,教程后面章节有讲。

2个月前 回复


avatar
zigzag 杜赛 [博主] 么么哒! 2

好的,我看到了,谢谢~wink

2个月前 回复


avatar
seekdoor 么么哒! 2

我发现一个奇怪的事情,在我添加了安全删除之后,功能都是正常的,然后把所有的文章都删除了。

现在使用了之前的表单填写文章的功能来添加了几篇文章, 但是点击添加完成后跳转的list页面需要刷新之后才能看到最新的列表,我记得在之前都是添加了之后就直接能显示出来的。

望赐教!

2个月前 回复


avatar
杜赛 [博主] seekdoor 么么哒! 2

在你怀疑有问题的代码处,多写几个print(),把相关的对象打印出来看看。

比如在 save() 附近 print,看看代码有没有执行。

2个月前 回复


avatar
ttr 么么哒! 3

博主你好,我调用layer.js无法弹出界面,并且控制台爆出错误:ReferenceError: confirm_delete is not defined,以下是代码

<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_delete()">删除文章</a>

                </div>
                <div class="col-12">
                        <p>{{article.body|safe}}</p>
                </div>
        </div>
</div>


<script>
        function confirm_delete(){
                layer.open({
                        title:"确认删除",
                        content:"确认删除这篇文章吗?",
                        yes:function(index,layero){
                                location.href="{% url 'article:article_delete'article.id%}"
                        },
                })
        }
</script>


 

2个月前 回复


avatar
杜赛 [博主] ttr 么么哒! 2

"{% url 'article:article_delete'article.id%}"

这里面是不是缺了个空格?改好试试。

2个月前 回复


avatar
ttr 杜赛 [博主] 么么哒! 3

博主您好,我根据您的提示改了一下,仍然没有弹出框,代码如下:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
文章详情
{% endblock title %}

{% 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_delete()">删除文章</a>

                </div>
                <div class="col-12">
                        <p>{{article.body|safe}}</p>
                </div>
        </div>
</div>

<script>
<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 %}

爆出错误如下:

TypeError: layer.open is not a function2 2:49:15

    confirm_delete http://127.0.0.1:8000/article/article-detail/2/:49

    onclick http://127.0.0.1:8000/article/article-detail/2/:1

 

我打开源码,点击layer,.js,jquery.js,可以显示代码,请问该如何解决?

2个月前 回复


avatar
杜赛 [博主] ttr 么么哒! 2

  • 为什么有两个 <script> 头部标签?
  •  layer.js 的载入是在 confirm_delte() 之前吗?

2个月前 回复


avatar
ttr 杜赛 [博主] 么么哒! 2

谢谢博主,我总算找到了错误,我把jquery.js的地址写错了,改过来就行了

2个月前 回复


avatar
1581779395@qq.com 么么哒! 1

记录一个错误:删除弹窗无效果:

Uncaught TypeError: layer.open is not a function
    at confirm_delete ((index):79)
    at HTMLAnchorElement.onclick ((index):61)

templates/article/detail.html
<script>
    // 删除文章的函数
    function confirm_delete() {
        // 调用layer弹窗组件
        layer.open({
            // 弹窗标题
            title: "确认删除",
            // 正文
            content: "确认删除这篇文章吗?",
            // 点击确定按钮后调用的回调函数
            yes: function(index, layero) {
                // 指定应当前往的 url
                location.href='{% url "article:article_delete" article.id %}'
            },
        })
    }
</script>

2个月前 回复


avatar
杜赛 [博主] 1581779395@qq.com 么么哒! 1

layer.js 没载入进来

2个月前 回复


avatar
1581779395@qq.com 杜赛 [博主] 么么哒! 1

是我的layer位置放错了吗?还是代码的问题 

2个月前 回复


avatar
杜赛 [博主] 1581779395@qq.com 么么哒! 1

都有可能。 html 代码是顺序执行的,试着把载入layer.js的代码放到 body 最前面去

2个月前 回复


avatar
1581779395@qq.com 么么哒! 1

博主你好,在这里碰到个问题,一直提醒我“

找不到'confirm_safe_delete'的反向键。'confirm_safe_delete'不是有效的视图函数或模式名称

国庆前遇到都,当时写到删除文章正常,写到安全删除就不正常了,求博主指点一下

1个月前 回复


avatar
杜赛 [博主] 1581779395@qq.com 么么哒! 1

url 反向解析的名称错了。检查模板中反向解析的名称和 urls.py 中的命名空间是否对应。

1个月前 回复


avatar
1581779395@qq.com 杜赛 [博主] 么么哒! 1

谢谢博主,解决了

1个月前 回复


avatar
fcmxmk 么么哒! 1

老师, 路径 templates/article/detail.html 定义的按钮名称"发送"无法生效, layer 好像只读取到 button 这个"按钮"样式, 内容读不到.
<form 
      style="display:none;" 
      id="safe_delete"
      action="{% url 'article:article_safe_delete' article.id %}" 
      method="POST"
      >
    {% csrf_token %}
    <button type="submit">发送</button>
</form>

21天前 回复


avatar
杜赛 [博主] fcmxmk 么么哒! 1

检查拼写错误,重点检查 layer 中的 css选择器和 form 是否对应

20天前 回复