中间件
# 实现中间件
class MiddleWare(object):
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, *args, **kwargs):
print('before')
ret = self.wsgi_app(*args, **kwargs)
print('after')
return ret
if __name__ == '__main__':
app.wsgi_app = MiddleWare(app.wsgi_app)
app.run()
# 源码片段
class Flask(_PackageBoundObject):
def run(self, host=None, port=None, debug=None,
load_dotenv=True, **options):
...
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
finally:
...
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
...
# 因为比before_request更靠前, 还没有request,需要自己处理environ
模板
# 模板文件目录默认templates, 可以在实列化时通过template_folder指定
# 示例
app = Flask(__name__, template_folder='templates')
# 静态文件目录默认static, 可以在实列化时通过static_folder指定,
app = Flask(__name__, static_folder='static')
# 静态文件前缀(别名)通过static_url_path指定
app = Flask(__name__, static_url_path=None)
# 源码片段
class Flask(_PackageBoundObject):
def __init__(
self,
import_name,
static_url_path=None,
static_folder='static',
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder='templates',
instance_path=None,
instance_relative_config=False,
root_path=None
):
...
# 渲染模板(语法和Django差别不大, 支持python语法)
from flask import render_template
# 示例
@app.route('/login/')
def login():
return render_template('login.html', **{'key': 'value'})
# 原型
def render_template(template_name_or_list, **context):
...
不同于django的是context参数接收关键字参数
###### 渲染普通变量 ######
# 后端
import time
@app.route('/test/')
def test():
return render_template('test.html',
tm=time.strftime('%Y-%m-%d', time.localtime()))
# test.html
<h1>{{ tm }}</h1>
# 页面显示
2017-08-09
###### 注意 ######
# flask和django一样做了防xss攻击, 渲染的变量是html标签字符串时需要处理
--- 方式一 ---
# 视图
from flask import Markup
return render_template('login.html', btn=Markup('<input type="submit" value="登录" / >'))
# login.html
{{ btn }}
--- 方式二 ---
# 视图
return render_template('account/login.html', btn='<input type="submit" value="登录" / >')
# login.html
{{ btn }}
###### 渲染字典 ######
# 视图
dic = {
1: {'name': 'a', 'gender': 'male', 'age': 18},
2: {'name': 'b', 'gender': 'female', 'age': 18},
}
@app.route('/test1/')
def test1():
return render_template('test1.html', dic=dic)
# test1.html
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
<th>gender</th>
</tr>
</thead>
<tbody>
{% for k, v in dic.items() %}
<tr>
<td>{{ k }}</td>
<td>{{ v.name }}</td>
<td>{{ v['age'] }}</td>
<td>{{ v.get('gender') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
# 页面显示
id name age gender
1 a 18 male
2 b 18 female
###### 渲染列表(元组) ######
# 视图
@app.route('/test2/')
def test2():
return render_template('test2.html', li=[1, 2, 3])
# 模板
<p>{{ li.0 }}</p>
<p>{{ li[2] }}</p>
<p>{{ li[-1::-1] }}</p>
{% for i in li %}
<span>{{ i }}</span>
{% endfor %}
# 页面显示
1
3
[3, 2, 1]
1 2 3
###### 渲染函数 ######
# 不同于django, flask需要加括号调用
# 视图
def func():
return '<h1>Hello Flask</h1>'
@app.route('/test3/')
def test3():
return render_template('test3.html', func=func)
# test3.html
<p>{{ func }}</p>
<p>{{ func() }}</p>
<p>{{ func.__name__ }}</p>
# 页面显示
<function func at 0x7f1c22d1fb70>
<h1>Hello Flask</h1>
func
###### 全局装饰器和全局过滤器 ######
# 同普通函数一样可以传参
# 视图
@app.template_global()
def hello():
return 'Hello Flask!'
# 模板
{{ hello() }}
# 过滤器
# 视图
@app.template_filter()
def is_even(v, a, b):
return not v % 2
# 模板
{% if 3|is_even('a', 'b') %}
even
{% endif %}
###### 模板继承 ######
# 语法和django一样
# base.html父模板
{% block content %}
{% endblock %}
# 子模板
{% extends 'base.html' %}
{% block content %}
...
{% endblock %}
###### 包含模板 ######
{% include 'menu.html' %}
###### 宏 ######
{% macro generate_input(name, type='text', value='') %}
<p>
<label for="id_{{ name }}">{{ name }}</label>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}" id="id_{{ name }}"/ >
</p>
{% endmacro %}
{{ generate_input('username') }}
{{ generate_input('password') }}
路由系统(本质就是url和函数对应关系)
###### 路由设置的两种方式 ######
*** 方式一 ***
@app.route('/index/')
def index():
return index
*** 方式二 ***
app.add_url_rule('/index/', None, index)
# 别名(默认等于函数名) endpoint不能重名
@app.route('/index/', endpoint='n1')
# 别名反向生成url
from flask import url_for
url_for('n1')
# 源码片段
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
###### 参数 ######
rule url规则
'/index/'
view_func 视图函数名称
view_func='home'
defaults 指定默认传参
defaults={'k': 'v'}
endpoint 名称, 用于反向生成URL, 默认视图名称
endpoint='home'
methods 允许的请求方式,默认只允许GET
methods=['POST', 'GET']
strict_slashes 对URL最后的/符号是否严格匹配, 默认True
strict_slashes=True
redirect_to 重定向指定地址
redirect_to='/login/'
subdomain 指定子域名访问
subdomain='admin'
app.config['SERVER_NAME'] = 'ret.com:5000'
###### 动态路由 ######
# 获取匹配字符
@app.route('/index/<nid>/')
# 获取匹配整数
@app.route('/index/<int:nid>/')
def index(nid):
return 'index'
url_for('index', nid=123)
# 自定义正则
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex
def to_python(self, value):
return value
def to_url(self, value):
return super(RegexConverter, self).to_url(value)
app.url_map.converters['reg'] = RegexConverter
@home.route('/index/<reg("\w{3}"):nid>/')
# 给视图添加自定义装饰器时,应该紧贴着放在函数上方