一. 静态文件访问原理
举例:
新建文件夹 app/static, 并在该文件夹下放入图片文件。
运行flask, 访问http://localhost:5000/static/图片名。
发现可以访问文件
flask是如何做到访问静态文件的呢? 我查看app/init.py的create_app中 app=Flask(name),Flask的源码:
def __init__(
self,
import_name,
static_url_path=None,
static_folder='static', # 默认的static文件的 路径
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder='templates', # 默认的template文件的路径
instance_path=None,
instance_relative_config=False,
root_path=None
):
以及通过注册视图函数的方式实现通过url访问static文件夹的:
if self.has_static_folder:
assert bool(static_host) == host_matching, 'Invalid static_host/host_matching combination'
self.add_url_rule( # 注册视图函数
self.static_url_path + '/<path:filename>',
endpoint='static',
host=static_host,
view_func=self.send_static_file
)
二. 模版文件的位置和修改方案
templates文件夹和static文件夹一样, 都是有默认设置的。我们放入app/templates文件下的html文件,都可以在视图函数中,通过render_template('html文件名')
来访问并返回给网站页面。
修改默认默认templates文件夹或static文件夹的位置, 我们可以对app = Flask(__name__)
添加参数来实现: 比如:
app = Flask(__name__, static_folder='static2', template_folder='tempaltes2')
# 这样static默认文件夹就在 app/static
# 这样templates默认文件夹就在 app/templates
我们可以对蓝图修改默认的static或templates文件夹位置
app/web/blueprint.py中这样修改
web = Blueprint('web', __name__, static_folder='static', template_folder='templates')
# 这样static文件夹在 app/web/static, 但static文件不建议这样, 因为static文件很可能不同的蓝图都会使用
# 这样templates文件夹在 app/web/templates
三. 使用Jinja2
1. 在Jinja2中读取字典和对象
Jinja2模糊了对象和dict, 在jinja2中访问他们方法是一样的 假设有视图函数:
@web.route('/test')
def test():
r = {
'name': 'cannon',
'age': 25
}
return render_template('test.html', data=r)
对应的test.html代码中:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title></title>
</head>
<body>
{{ data.age }}
{{ data['age'] }}
</body>
</html>
2. 流程控制语句
if语句
test.html:
<body>
{{ data.age }}
{{ data['age'] }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
do something
{% else %}
{{ data.age }}
{% endif %}
</body>
for in循环
test.html:
<body>
{% for key, value in data.items() %}
{{ key }}
{{ value }}
{% endfor %}
</body>
3. 使用模版继承
layout.html:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title></title>
</head>
<body>
{% block head %}
<div> This is head </div>
{% endblock %}
{% block content %}
This is content
{% endblock %}
{% block foot %}
<div> This is foot </div>
{% endblock %}
</body>
</html>
在别的html页面继承layout.html
test.html:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{{ data.age }}
{{ data['age'] }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
do something
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}
4. 过滤器与管道命令
过滤器
1. default
test.html:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{{ data.age }}
{{ data['age'] }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
{{ data.school | default('不存在') }} {# 访问不存在的变量,default才会生效 #}
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}
如果想data.school=None时,default也生效, 使用default('不存在', true) (加上一个true参数)
2. length
test.html:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{{ data.age }}
{{ data['age'] }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
{{ data | length() }} {# 得到data的长度 #}
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}
3. 更多的过滤使用方法,可以去官方文档查看
四. urlfor 反向构建URL
以前注册视图函数的时候, 有个endpoint参数,我们并没有说它的作用。endpoint其实是用来反向获取url的。
新建app/static/test.css, 现在我想让app/templates/layout.html去加载test.css:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title></title>
<link rel="stylesheet" href="{{ url_for('static', filename='test.css') }}">
{# url_for的使用方法 第一个参数是endpoint #}
{# <link rel="stylesheet" href="/static/test.css">#}
</head>
<body>
{% block head %}
<div> This is head</div>
{% endblock %}
{% block content %}
This is content
{% endblock %}
{% block foot %}
<div> This is foot</div>
{% endblock %}
</body>
</html>
flask中能用url_for的, 尽量都用url_for
五. 消息闪现、SecretKey与变量作用域with
1.消息闪现 Messageing Flash
我们在app/web/book.py修改test视图函数:
from flask import flash
@web.route('/test')
def test():
r = {
'name': None,
'age': 18
}
flash('hello, cannon') # 使用flash
return render_template('test.html', data=r)
对app/templats/test.html做修改:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
{{ data | length() }}
{% set messages = get_flashed_messages() %} {# 对应的使用get_flashed_messages #}
{{ messages }}
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}
我们运行flask并访问localhost:5000/test
,报错了:
消息闪现使用到了 session, 我们需要在配置文件secure.py添加secretkey:
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:@localhost:3306/fisher'
SECRET_KEY = 'wjdiajsjkskcnndijqwiodjieijqijwiwqijfbryguhtrvwpqwqdnxjj'
运行后得到结果:
This is head
This is content
['hello, cannon'] # flash得到的数据
This is foot
2.category参数的使用
修改app/web/book.py的test视图函数, 加入category参数:
from flask import flash
@web.route('/test')
def test():
r = {
'name': None,
'age': 18
}
flash('hello, cannon', category='error') # 使用flash
flash('hello, cannon2', category='worning') # 使用flash
return render_template('test.html', data=r)
修改app/templats/test.html:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
{{ data | length() }}
{% set messages = get_flashed_messages(category_filter=['error']) %}
{# category参数对应使用category_filter #}
{{ messages }}
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}
这样 只会显示 category为error的flash传递的数据
3.with缩小变量作用域
在Jinja2中使用with语句, 则变量作用域只在with 和endwith之间:
修改app/templats/test.html:
{% extends 'layout.html' %}
{% block content %}
{{ super() }}
{% if data.age < 18 %}
{{ data.name }}
{% elif data.age == 18 %}
{{ data | length() }}
{% with messages = get_flashed_messages(category_filter=['error']) %}
{{ messages }} {# messages可以显示 #}
{% endwith %}
{{ mesages }} {# messages不能显示 #}
{% else %}
{{ data.age }}
{% endif %}
{% endblock %}