@@ 2020-12-14 @@
Preface
flask-bootstrap 是用于 flask 框架中一个 pip 包,通过 jinja2 模板继承特性可以快速开发 bootstrap。
但这个包默认采用的是 cloudflare 源,默认会包含 bootstrap.css、bootstrap.js、jquery.js,此外还可以包含 html5shiv、respond.js,这个可以通过一定方法查看,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
In [1]: from flask import Flask
In [2]: from flask_bootstrap import Bootstrap
In [3]: app = Flask(__name__)
In [4]: bootstrap = Bootstrap(app)
In [5]: app.extensions
Out[5]:
{'bootstrap': {'cdns': {'local': <flask_bootstrap.StaticCDN at 0x743831b0>,
'static': <flask_bootstrap.StaticCDN at 0x743b9e50>,
'bootstrap': <flask_bootstrap.ConditionalCDN at 0x743a4fb0>,
'jquery': <flask_bootstrap.ConditionalCDN at 0x743dd550>,
'html5shiv': <flask_bootstrap.ConditionalCDN at 0x743cf3d0>,
'respond.js': <flask_bootstrap.ConditionalCDN at 0x743cf5d0>,
'bootcdn_bootstrap': <flask_bootstrap.ConditionalCDN at 0x743cf0f0>,
'bootcdn_jquery': <flask_bootstrap.ConditionalCDN at 0x743cf4b0>}},
'nav_renderers': {'bootstrap': ('flask_bootstrap.nav', 'BootstrapRenderer'),
None: ('flask_bootstrap.nav', 'BootstrapRenderer')}}
|
但是在国内,cloudflare 的速度真是令人感动。
纵观一圈网上的解决方法,总体来说分两种思路:(1) 在 __init__.py 暴力修改 (2) 修改 flask-bootstrap package
第一种方法代码量较大,并且暴力修改代码使其可读性大大降低;第二种方法在环境变了或者包更新了的情况都需要重新配置,太麻烦了。
Inplement
一个包的主体部分是不会变的,那么我们在项目主入口用类继承重写一下方法就行了,并且在模板继承时重写 bootstrap/base.html 中的 styles 和 scripts
Recette
这里采用 bootcdn 作范例
首先要读源码,了解 flask-bootstrap 这个包怎么运行,我就不写怎么读了(
包目录
~/venv/lib/python3.x/site-packages/flask_bootstrap
我们知道 Python 在 import flask-bootstrap 时,其实就是 import 了这个目录下的__init__.py
再通过对象方法调用相应的类,from flask-bootstrap import Bootstrap 就是直接导入了 Bootstrap 这个类
我们需要用到__init__.py
中以下类/包变量
Bootstrap, ConditionalCDN, WebCDN, StaticCDN, BOOTSTRAP_VERSION, JQUERY_VERSION
Initialization
1
2
|
from flask import Flask
from flask_bootstrap import Bootstrap, ConditionalCDN, WebCDN, StaticCDN, BOOTSTRAP_VERSION, JQUERY_VERSION
|
Rewrite inherited class function
1
2
3
4
5
6
7
8
9
10
11
|
class Bootstrap_with_bootcdn(Bootstrap): # 子类
def init_app(self, app): # 重写
super().init_app(app) # 继承
local = StaticCDN('bootstrap.static', rev=True)
static = StaticCDN()
def lwrap(cdn, primary=static):
return ConditionalCDN('BOOTSTRAP_SERVE_LOCAL', primary, cdn)
bootcdn_bootstrap = lwrap(WebCDN('//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/%s/' % BOOTSTRAP_VERSION), local)
bootcdn_jquery = lwrap(WebCDN('//cdn.bootcdn.net/ajax/libs/jquery/%s/' % JQUERY_VERSION), local)
app.extensions['bootstrap']['cdns']['bootcdn_bootstrap'] = bootcdn_bootstrap
app.extensions['bootstrap']['cdns']['bootcdn_jquery'] = bootcdn_jquery
|
我在此处加入了两条键,分别是bootcdn_bootstrap
和bootcdn_jquery
,在后面模板重写需要用到
如果你想加入别的 CDN,只需要按照上面的规则添加就行了
再将其实例化
1
2
|
app = Flask(__name__)
bootstrap = Bootstrap_with_bootcdn(app)
|
Rewrite inherited template block
1
2
3
4
5
6
7
8
|
{% block styles %}
<link href="{{ bootstrap_find_resource('css/bootstrap.css', cdn='bootcdn_bootstrap') }}" rel="stylesheet">
{% endblock %}
{% block scripts %}
<script src="{{ bootstrap_find_resource('jquery.js', cdn='bootcdn_jquery') }}"></script>
<script src="{{ bootstrap_find_resource('js/bootstrap.js', cdn='bootcdn_bootstrap') }}"></script>
{% endblock %}
|
我们知道 super() 是类继承用的函数,但是这在模板继承也可以用到,并且具有非常类似的作用,如果不在 block 中加入 super(),会默认使用子模板的同名 block 覆盖父模板中的同名 block
这里的 bootstrap_find_resource 方法中的属性 cdn 要对应我们之前重写的类属性
Others - Optimization
我们可以将以上代码打包放进config.py
,这是我比较推荐的一种方式
./config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from flask_bootstrap import Bootstrap, ConditionalCDN, WebCDN, StaticCDN, BOOTSTRAP_VERSION, JQUERY_VERSION
class Bootstrap_with_bootcdn(Bootstrap):
def init_app(self, app):
super().init_app(app)
local = StaticCDN('bootstrap.static', rev=True)
static = StaticCDN()
def lwrap(cdn, primary=static):
return ConditionalCDN('BOOTSTRAP_SERVE_LOCAL', primary, cdn)
bootcdn_bootstrap = lwrap(WebCDN('//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/%s/' % BOOTSTRAP_VERSION), loca
l)
bootcdn_jquery = lwrap(WebCDN('//cdn.bootcdn.net/ajax/libs/jquery/%s/' % JQUERY_VERSION), local)
app.extensions['bootstrap']['cdns']['bootcdn_bootstrap'] = bootcdn_bootstrap
app.extensions['bootstrap']['cdns']['bootcdn_jquery'] = bootcdn_jquery
|
./app.py
1
2
3
4
|
from config import Bootstrap_with_bootcdn
app = Flask(__name__)
bootstrap = Bootstrap_with_bootcdn(app)
|