轻松理解 Flask 中的 static 目录

初学 Flask 的人都知道, Flask 的模板文件默认放在 “templates” 文件夹下, 静态资源文件放在 “static” 目录下, 只要照着规矩走, 一点事都没有.

但是为了和我的历史项目结构保持一致性 (加上强迫症), 对 Flask 的默认路径不喜欢, 想把文件这样放:

myproject/
|-layout/  # 原 templates 目录
	|-index.html
|-res/  # 原 static 目录

结果意想不到地踩了很多坑, 花了一星期的时间终于弄清楚了.

本文是为了帮大家 (轻松) 理解 Flask 的 static_folder 参数的作用.


为了方便理解, 本文通过一个例子讲解.

假设测试项目的目录结构如下:

myproject/
|-A/
	|-B/
		|-b.js
	|-a.js
	|-index.html  # 启动界面
	|-launch.py  # 启动脚本
|-C/
	|-c.js
|-d.js

其中每个 js 文件都是测试脚本, 里面就非常简单的一句话:

console.log('x.js')  // x 填对应的文件名

launch.py 测试代码:

# A/launch.py
from flask import Flask, render_template

app = Flask(
    __name__,
    template_folder='.',  # 表示在当前目录 (myproject/A/) 寻找模板文件
    static_folder='../',  # 表示为上级目录 (myproject/) 开通虚拟资源入口
    static_url_path='',  # 这是路径前缀, 个人认为非常蛋疼的设计之一, 建议传空字符串, 可以避免很多麻烦
)


@app.route('/')
def main():
    return render_template(
        'index.html'
    )


if __name__ == '__main__':
    app.run()


index.html 测试代码:

<!-- A/index.html -->
<script src="d.js"></script><!-- 猜猜哪个能找到真正的 d.js (Flask 另一个坑) -->
<script src="../d.js"></script>
<script src="../../d.js"></script>
<script src="../../../d.js"></script>
<script src="a.js"></script>
<script src="A/a.js"></script>
<script src="A/B/b.js"></script>
<script src="C/c.js"></script>


注意, 在开始测试时, 打开浏览器的开发者模式, 并在 network 选项卡把 “Disable cache” 勾选上:

1555419936146.png

(这样可以避免浏览器使用缓存的测试文件, 避免上次测试结果干扰下次测试.)


测试结果:

1555419991317.png


解释一下上面的结果:

<!-- A/index.html -->
<script src="d.js"></script><!-- 指向 myproject/d.js (ok) -->
<script src="../d.js"></script><!-- 指向 myproject/d.js (ok)-->
<script src="../../d.js"></script><!-- 指向 myproject/d.js (ok)-->
<script src="../../../d.js"></script><!-- 指向 myproject/d.js (ok)-->
<script src="a.js"></script><!-- 指向 myproject/a.js (不存在, 报错) -->
<script src="A/a.js"></script><!-- 指向 myproject/A/a.js (ok)-->
<script src="A/B/b.js"></script><!-- 指向 myproject/A/B/b.js (ok)-->
<script src="C/c.js"></script><!-- 指向 myproject/C/c.js (ok)-->


结论:

  1. 在 Flask 中, HTML 的相对路径逻辑完全失效, 只能按照 Flask 的逻辑来走
  2. Flask 的逻辑是以 Flask.__init__() 中的 static_folder 参数为准
    [外链图片转存失败(img-lQaVwhCy-1563030961553)(https://i.loli.net/2019/04/17/5cb71a338c608.png)]
  3. static_folder 的路径是 相对于 启动文件 (本例中的 myproject/A/launch.py) 设置的. 也就是说默认情况下, 只有 myproject/A/static/ (本项目中未创建) 为虚拟资源的目录入口的. 所以这里我把 static_folder 设为 “…/” 就是为了能够让 Flask 以 myproject/ 为虚拟资源的入口
  4. 由于 static_folder 不允许向上查找路径 (这也就是为什么 HTML 中的 “…/…/…/” 居然都指向同一个值的原因), 也就是说 “…/…/…/…” 之类的父级路径符号, 都会被删除掉 — 可以变相地认为, 一旦 static_folder 设置了一个目录, 则该目录的所有上级目录的资源都将无法访问


顺便再举一个例子, 我把 static_folder="../" 改为 static_folder="." 看看会发生什么:

# A/launch.py
from flask import Flask, render_template

app = Flask(
    __name__,
    template_folder='.',  # 表示在当前目录 (myproject/A/) 寻找模板文件
    static_folder='.',  # 表示为当前目录 (myproject/A/) 开通虚拟资源入口
    static_url_path='',
)


@app.route('/')
def main():
    return render_template(
        'index.html'
    )


if __name__ == '__main__':
    app.run()


测试结果:

[外链图片转存失败(img-CXeoZWKh-1563030961554)(https://i.loli.net/2019/04/17/5cb71a3588420.png)]

解释一下上面的结果:

<!-- A/index.html -->
<script src="d.js"></script><!-- 指向 myproject/A/d.js (报错) -->
<script src="../d.js"></script><!-- 指向 myproject/A/d.js (报错) -->
<script src="../../d.js"></script><!-- 指向 myproject/A/d.js (报错) -->
<script src="../../../d.js"></script><!-- 指向 myproject/A/d.js (报错) -->
<script src="a.js"></script><!-- 指向 myproject/A/a.js (ok) -->
<script src="A/a.js"></script><!-- 指向 myproject/A/A/a.js (报错) -->
<script src="A/B/b.js"></script><!-- 指向 myproject/A/A/B/b.js (报错) -->
<script src="C/c.js"></script><!-- 指向 myproject/A/C/c.js (报错) -->


相信大家从上述例子中, 也能对 static_folder 心里有个底了.

当然 static_url_for 这个参数为什么传空字符串我还没有谈, 总之加上这货才是完成了 Flask 的连环坑.

我这里简单讲一下, static_url_for 缺省值是 None, 也就是会在实例化完成后解释. 它的作用是每当我们从虚拟资源目录入口寻找资源时, 自动帮我们定位到资源目录下的 “static” 文件夹中查找 (不管这个文件夹是否存在). 而当我们在初始化 Flask 实例时给它赋值空字符串, 就能避免它自作聪明了.

  • 20
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值