类似于Django中间件的特殊装饰器


1.before_request 装饰器

  • before_request 装饰器 相当于Django中间件中的 process_request 方法

  • 当一个函数使用了 before_request 装饰器,那么所有视图函数在执行前都会先执行该函数

  • 返回值:

    • 可以没有返回值

    • 如果返回 None: 跳出当前 before_request 装饰器所装饰的函数,直接执行视图函数

    • 如果返回 字符串、数字、render_template、redirect、jsonify: 直接返回给浏览器,不执行下面的视图函数

# app.py

from flask import Flask, request, render_template

app = Flask(__name__)


@app.before_request
def xxx():
    print('before_request')
    if request.path == '/login':
        return None
    else:
        return 'index2'


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

  • 多个 before_request 装饰器的执行顺序

    • 先定义的先执行

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.before_request
def b1():
    print('before_request1')


@app.before_request
def b2():
    print('before_request2')


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- index 视图 ----------------

before_request1
before_request2
index

# --------------- login 视图 ----------------

before_request1
before_request2
login

2.after_request 装饰器

  • after_request 装饰器 相当于Django中间件中的 process_response 方法

  • 当一个函数使用了 after_request 装饰器,那么所有的视图函数都会在执行完后再执行该函数

  • 参数: 必须接收一个参数

  • 返回值:

    • 必须要有返回值

    • 不能返回 None,如果返回None相当于没有返回值

    • 可以直接返回接收到的参数

    • 可以返回 字符串、数字、render_template、redirect、jsonify

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.after_request
def xxx(response):
    print('after_request')
return response


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

  • 多个 after_request 装饰器的执行顺序

    • 后定义的先执行

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.after_request
def a1(response):
    print('after_request1')
    return response


@app.after_request
def a2(response):
    print('after_request2')
    return response


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- index 视图 ----------------

index
after_request2
after_request1

# --------------- login 视图 ----------------

login
after_request2
after_request1

3.before_request 和 after_request 的执行顺序

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.before_request
def b_r():
    print('before_request')


@app.after_request
def a_r(response):
    print('after_request')
    return response


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- index 视图 ----------------

before_request
index
after_request

# --------------- login 视图 ----------------

before_request
login
after_request


4. 多个 before_request 和 after_request 的执行顺序

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.before_request
def b1():
    print('before_request1')


@app.before_request
def b2():
    print('before_request2')


@app.after_request
def a1(response):
    print('after_request1')
    return response


@app.after_request
def a2(response):
    print('after_request2')
    return response


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- index 视图 ----------------

before_request1
before_request2
index
after_request2
after_request1

# --------------- login 视图 ----------------

before_request1
before_request2
login
after_request2
after_request1


5. 当 before_request有返回值的执行顺序

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.before_request
def b1():
    print('before_request1')
return 'test_index'


@app.before_request
def b2():
    print('before_request2')


@app.after_request
def a1(response):
    print('after_request1')
    return response


@app.after_request
def a2(response):
    print('after_request2')
    return response


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- index 视图 ----------------

before_request1
after_request2
after_request1

# --------------- login 视图 ----------------

before_request1
after_request2
after_request1


其他特殊装饰器


1.before_first_request装饰器

  • 只有在第一次请求之前调用(即: 只会执行一次)

  • 返回值:

    • 可以没有返回值

    • 如果返回 None: 跳出当前 before_request 装饰器所装饰的函数,直接执行视图函数

    • 如果返回 字符串、数字、render_template、redirect、jsonify: 直接返回给浏览器,不执行下面的视图函数

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.before_first_request
def one():
    print('before_first_request')


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


@app.route('/login')
def login():
    print('login')
    return render_template('login.html')


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

# 执行结果

# --------------- 第一次 index 视图 ----------------

before_first_request
index

# --------------- 第二次 login 视图 ----------------

login

2.template_global() 装饰器

  • 全局模板函数

  • 全局模板函数作用于所有模板(即: 在任何模板中都可以调用该方法)

  • 两种作用: 

    • template_global() 装饰器 和 Django 模板语言中的 inclusion_tag 类似

    • 当有两个或以上的视图函数都需要传递同一个函数给自身模板的时候可以使用全局模板函数

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.template_global()
def t_fn(n1, n2, n3):
    return n1 + n2 + n3


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


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

# index.html

{{'{'+'{'+' t_fn(1, 2, 3) '+'}'+'}'}}

3.template_filter()装饰器

  • 自定义过滤器

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.template_filter()
def t_filter(n1, n2, n3):
    print(n1, n2, n3)  # 2 3 4
    return n1 + n2 + n3


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


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

# index.html

{{'{'+'{'+' 2|t_filter(3, 4) '+'}'+'}'}}

4.errorhandler(错误状态码)装饰器

  • 自定义错误信息页面

  • 当发生 404 或 500 等错误状态码的时候就会返回自定义的错误信息页面给浏览器,而不是 flask 的错误信息

# app.py

from flask import Flask, render_template

app = Flask(__name__)


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


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


@app.errorhandler(404)
def not_found(error_msg):
    print(error_msg)  # 错误信息
    return render_template('error.html')


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