1、关于上下文的介绍

Flask项目中有两个上下文,一个是应用上下文(app),另外一个是请求上下文(request)请求上下文request和应用上下文current_app都是一个全局变量。所有请求都共享的。Flask有特殊的机制可以保证每次请求的数据都是隔离的,即A请求所产生的数据不会影响到B请求。所以可以直接导入request对象,也不会被一些脏数据影响了,并且不需要在每个函数中使用request的时候传入request对象。这两个上下文具体的实现方式和原理可以没必要详细了解

  • request:请求上下文上的对象。这个对象一般用来保存一些请求的变量。比如method、args、form等。

image.png

  • session:请求上下文上的对象。这个对象一般用来保存一些会话信息。(原理与request相似)
  • current_app:返回当前的app。

代码部分:
config.py文件

  1. DEBUG = True
  2. TEMPLATES_AUTO_RELOAD = True

current_app_dome.py文件

  1. from flask import Flask, current_app, render_template
  2. import config
  3. app_dome = Flask(__name__)
  4. app_dome.config.from_object(config)
  5. @app_dome.route("/")
  6. def home():
  7. print(current_app.name)
  8. print(current_app.config["TEMPLATES_AUTO_RELOAD"])
  9. return render_template('index.html')
  10. if __name__ == '__main__':
  11. app_dome.run()

返回:
image.png
注意点:
1、current_app不能再函数外部进行使用:会报错

  1. # print(current_app.name)
  2. # print(current_app.config["TEMPLATES_AUTO_RELOAD"])
  3. @app_dome.route("/")
  4. def home():
  5. return "首页"

2、current_app指代的是当前app这个对象,与你命名的app或者app123无关
3、通过current_app.config[“xxx”]可以获取到现在配置的对应值,但是需要在文件中已经进行配置的

  • 可以是通过from_object()进行导入的
  • 可以是通过app.config[‘xxx’] = yyy进行写入的
    • g:应用上下文上的对象。处理请求时用作临时存储的对象。(所谓临时,就是指在每次刷新页面都会使g对象重置)

g对象能够很好的防止反复传参
现在我们定义了一个工具文件utils.py,其中需要由主入口文件生成的session信息
utils.py文件

  1. def make_name(username):
  2. print(username)

主入口文件

  1. from flask import Flask, session, g
  2. app = Flask(__name__)
  3. app.config["SECRET_KEY"] = os.urandom(12)
  4. app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=1)
  5. @app.route("/")
  6. def home():
  7. name = session['name']
  8. g.name = name
  9. print(make_name(g.name))
  10. return "首页"
  11. @app.route("/login/")
  12. def login():
  13. session['name'] = 'gongzhujun'
  14. session['password'] = "147258"
  15. session.permanent = True
  16. return '登录页'
  17. if __name__ == '__main__':
  18. app.run(debug=True)

虽然这样可以获取的最后的结果,如果需求量大,那会出现反复传参的情况,于是对其进行改造
utils.py文件

  1. from flask import g
  2. def make_name():
  3. print(g.name)

主入口文件:

  1. from flask import Flask, session, g
  2. from utils import make_name
  3. app = Flask(__name__)
  4. app.config["SECRET_KEY"] = os.urandom(12)
  5. @app.route("/")
  6. def home():
  7. name = session['name']
  8. password = session['password']
  9. g.name = name
  10. g.password = password
  11. print(make_name())
  12. # 调用自己内部定义的方法
  13. getpassword()
  14. return "首页"
  15. def getpassword():
  16. print(g.password)
  17. @app.route("/login/")
  18. def login():
  19. session['name'] = 'gongzhujun'
  20. session['password'] = "147258"
  21. session.permanent = True
  22. return '登录页'
  23. if __name__ == '__main__':
  24. app.run(debug=True)

返回结果:
image.png
在此强调:1、在这个例子中,只有先上传session,g才能获取到对应的值2、g在页面刷新时,会被重置
**

2、钩子函数

1、第一部分-请求前后执行

来一段代码感受一下:

  1. from flask import Flask
  2. app = Flask(__name__)
  3. @app.route("/")
  4. def home():
  5. print("这是首页")
  6. return "首页"
  7. @app.before_first_request
  8. def first_request():
  9. print("第一次请求之前")
  10. @app.before_request
  11. def before_request():
  12. print("每次请求都被执行")
  13. @app.after_request
  14. def after_request(response):
  15. print("每次请求之后被执行")
  16. return response
  17. @app.teardown_appcontext
  18. def teardown_appcontext(response):
  19. print("teardown_appcontext被执行")
  20. return response
  21. if __name__ == '__main__':
  22. app.run(debug=True)

返回结果:
image.png
注意点:
1、如果是在请求之后执行的钩子函数,需要传入response这一参数
2、如果开启debug模式,在页面报错的情况下,请求之后的钩子函数将不会被执行
3、当在次发生请求时,before_first_request将不再被执行
代码解析:

  • before_first_request:处理第一次请求之前执行:

    1. @app.before_first_request
    2. def first_request():
    3. print("第一次请求之前")
  • before_request:在每次请求之前执行。通常可以用这个装饰器来给视图函数增加一些变量

    1. @app.before_request
    2. def before_request():
    3. print("每次请求都被执行")
  • after_request:每次请求之后都被执行(需要注意的是在开启debug模式并且页面报错时将不再执行,如果只是出现异常也会运行,需要传入response)

    1. @app.after_request
    2. def after_request(response):
    3. print("每次请求之后被执行")
    4. return response
  • teardown_appcontext:不管是否有异常,注册的函数都会在每次请求之后执行(同after_request)

    1. @app.teardown_appcontext
    2. def teardown_appcontext(response):
    3. print("teardown_appcontext被执行")
    4. return response

    2、第二部分-定义上下文处理器(context_processor)返回数据到模板中

    context_processor:上下文处理器。返回的字典中的键可以在模板上下文中使用

    1. @app.context_processor
    2. def context_processor():
    3. return {'current_user':'xxx'}

    具体应用:
    ```python from flask import Flask, render_template

app = Flask(name)

@app.context_processor def context(): return { “title1”: “这是首页”, “title2”: “这是登录页” }

@app.route(“/“) def home(): return render_template(“home.html”)

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

if name == ‘main‘: app.run(debug=True)

  1. login.html
  2. ```python
  3. <!DOCTYPE html>
  4. <html lang="en">
  5. <head>
  6. <meta charset="UTF-8">
  7. <title>login</title>
  8. </head>
  9. <body>
  10. <!-- 直接引用title2 -->
  11. {{ title2 }}
  12. </body>
  13. </html>

home.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>home</title>
  6. </head>
  7. <body>
  8. <!-- 直接引用title1 -->
  9. {{ title1 }}
  10. </body>
  11. </html>

返回结果:
image.png
image.png

3、第三部分-接收状态码(errorhandler(需要捕获的状态码))

errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。

  1. @app.errorhandler(404)
  2. def page_not_found(error):
  3. return 'This page does not exist',404

捕获异常小例子(为了正常显示关闭debug模式):

  1. from flask import Flask, render_template
  2. # 主动抛出异常,让errorhandler进行捕获
  3. from flask import abort
  4. app = Flask(__name__)
  5. @app.route("/")
  6. def home():
  7. # 主动抛出400的异常
  8. abort(404)
  9. return "首页"
  10. @app.route("/list/")
  11. def list():
  12. # 定义一个系统错误,状态码为500
  13. 1/0
  14. return "这是列表页"
  15. @app.errorhandler(404)
  16. # error是一个形参,必须要写
  17. def no_find(error):
  18. # 在后面写上400的原因是,使网页中显示的状态码也为404
  19. return render_template("404.html"), 404
  20. @app.errorhandler(500)
  21. def make_error(error):
  22. return "服务器内部错误", 500
  23. if __name__ == '__main__':
  24. app.run(debug=True)

页面显示:
404错误
image.png
500错误
image.png
代码解读:
主动抛出异常(abort(状态码))

  1. from flask import abort

接收异常的种类:

  1. @app.errorhandler(404)
  2. # 不要忘记传入一个形参,一般是error
  3. def no_find(error):
  4. # 在后面写上400的原因是,使网页中显示的状态码也为404
  5. return render_template("404.html"), 404
  6. # return "页面丢失",404