Flask学习笔记

1. 路由解惑 @app.route("/about/")@app.route("/about")
是不一样的
官方文档解释是:前者类似于文件系统的文件夹,后者类似于文件系统唯一的路径。
也就是说,开发时使用前者,用户访问时可以带或者不带后面的斜杠,Flask会默认带上;使用后者,用户只能按约定使用一个斜杠。

The canonical URL for the projects endpoint has a trailing slash. It’s similar to a folder in a file system. If you access the URL without a trailing slash, Flask redirects you to the canonical URL with the trailing slash.
The canonical URL for the about endpoint does not have a trailing slash. It’s similar to the pathname of a file. Accessing the URL with a trailing slash produces a 404 “Not Found” error. This helps keep URLs unique for these resources, which helps search engines avoid indexing the same page twice.
2. Blueprint Resource Folder Blueprint的第二个参数通常是__name__.这个参数指定blueprint对应的逻辑python包或模块。如果它指向一个实际的python包(这个包在文件系统中)是资源目录(resource folder)如果这是个模块,这个模块所在的包,将会是resource folder.
可以访问Blueprint.root_path属性查看是什么文件夹:
>>>simple_page.root_path '/users/username/TestProject/yourapplication'

可以使用open_resource()函数快速打开资源文件夹:
with simple_page.open_resource('static/style.css') as f: code = f.read()

3. Static Files 一个blueprint可以通过使用static_folder参数提供文件系统上的路径暴露一个含有静态文件的文件夹。
admin = Blueprint('admin',name, static_folder= 'static' )
4. Templates 5. The Application Context(应用上下文) 应用上下文跟踪应用级别的数据在一个请求,CLI 命令或者其他活动内。不是经过应用给每一个函数,而是使用current_app和g代替。
这一点和请求上下文很相似,请求上下文跟踪一个请求级别的数据在一个请求内。当一个请求上下文被入栈相应的应用上下文被入栈。
5.1 上下文的意图 Flask 应用对象有属性,比如config,对范文视图函数和CLI command很有用。然而,在你的项目的模块中引入app实例很容易引起循环引入的问题。当使用app factory pattern 或者写一个可复用的blueprints或扩展就没有必要导入一个app实例
Flask 通过application context来解决这个问题。不是直接使用app,而是使用current_app proxy(代理),
它指向处理当前活动的应用。
Flask 自动入栈(push)一个应用上下文当处理请求的时候。在一个请求内的view functions,error handlers and other functions将会访问current_app.
Flask也将自动入栈一个app 上下文当运行一个用Flask.cli(使用@app.cli.command())注册的CLI 命令时。
5.2 上下文的生命周期 应用上下文的创造和销毁随需要进行的。当一个Flask应用开始处理一个请求,它入栈一个应用上下文和一个请求上下文。当一个请求结束时它出栈一个请求上下文然后一个应用上下文。经典地,一个应用上下文和一个请求具有相同的生命周期。
5.3 手动入栈一个上下文(Manually Push a Context) 【Flask学习笔记】如果你试图访问一个current_app。或者其他任何你使用的,超出应用上下文的,你将会得到一个错误信息:
RuntimeError: Working outside of application context.This typically means that you attempted to use functionality that needed to interface with the current application object in some way. To solve this, set up an application context with app.app_context().

如果你正在配置应用时看到这个错误,你可以手动入栈一个上下文,因为你可以直接访问app。 在一个 with 块中使用app_context(),运行在这个块中的一切都可以访问current_app
如果你在和配置无关的地方看到这个错误,最可能暗示你应该移动代码到一个试图函数里或CLI 命令里。
5.4 存储数据 在一个请求或CLI command内,应用上下文是一个存储数据的好地方。Flask 提供 g object为了这个意图。这是一个简单的命名空间和应用上下文有相同的生命周期。
Note:
g 表示"global" ,但它指的是上下文中的全部数据。上下文结束后g中的数据将会丢失,而且也不是一个适合在请求之间存储数据的好地方。使用 session 或者数据库来存储跨请求的数据。
g 常用来在一个请求内管理资源。
  1. get_X() 创造资源X。如果它不存在,缓存它作为g.X
  2. teardown_X() 关闭资源或其他解除资源。它被注册为teardown_appcontext()处理器
for example,你可以使用这个模式管理数据库连接:
from flask import gdef get_db(): if 'db' not in g: g.db = connect_to_database()return g.db@app.teardown_appcontext def teardown_db(): db = g.pop('db', None)if db is not None: db.close()

6. (The Request Context)请求上下文 请求上下文在一个请求内跟踪请求级的数据。不是将请求对象传递给每一个函数,request和session代理是可以访问的。
请求上下文的意图
当Flask应用处理请求的时候,它创建一个Request对象根据环境它从WSGI服务器接收。因为worker(thread, process, or coroutine depending on the server)一次只能处理一个请求,请求数据可以被认为是这个worker的全局数据。为此Flask 使用术语 context local
Flask 自动入栈一个请求上下文。在一个请求内的view functions, error handlers,和其他functions将可以使用request代理,它将指向当前请求的请求对象。
6.1 上下文的生命周期 当一个Flask应用开始处理请求的时候,它自动入栈一个请求上下文,也入栈一个应用上下文。当请求结束时,它出栈一个请求上下文之后出栈一个应用上下文。
对每一个线程(或其他工作类型),上下文是独一无二的。request不能被带到其他线程,其他线程会有一个不同的上下文栈而且不知道父线程指向的request.
Context locals在Werkzeug中实现。
6.2 手动入栈一个上下文 如果你尝试访问一个request,或者其他使用request,你将会得到一个错误信息:
RuntimeError: Working outside of request context.This typically means that you attempted to use functionality that needed an active HTTP request. Consult the documentation on testing for information about how to avoid this problem.

这经常出现在测试代码中,测试代码期望一个激活的request.一个选项是使用test_client来模拟一个完整的request.或者你可以在with块中使用test_request_context(),运行在块中的一切都可以访问request,用测试数据填充。
def generate_report(year): format = request.args.get('format') ...with app.test_request_context( '/make_report/2017', data=https://www.it610.com/article/{'format': 'short'}): generate_report()

如果你在和测试无关的地方看到这个错误,很可能你应该把代码放到视图函数里。
6.3 How the Context Works
Flask.wsgi_app()方法被调用来处理每一个请求。它在请求期间管理上下文。内部,请求上下文和应用上下文的工作形式为栈,_request_ctx_stack 和 _app_ctx_stack.当上下文被入栈,依赖他们的栈是可得到的,并且指向来自栈顶上下文的信息。
当请求开始的时候,一个RequestContext被创建和被入栈,它创建并入栈一个AppContext如果这个应用的上下文没有已经存在上下文顶部。当这些上下文都被入栈,current_app, g, request, session代理就可以得到对原本的的线程处理请求。
因为上下文是栈,在一个请求内其他上下文可能被入栈从而改变代理。尽管这不是一个通用的模式,它仍然可以被使用在高级应用中,举例,在内部重定向或链到不同的应用。
请求被调配和相应被注册和发送后,请求上下文被出栈,之后出栈应用上下文。在他们被弹出之前,teardown_request()和tear_appcontext()函数会被执行。这些执行尽管未处理的异常发生在调配期间。
6.4 Callbacks and Errors Flask 在多个阶段调度一个请求可以影响request, response 和怎么处理一个错误。这些上下文被激活在所有阶段。
一个Blueprint可以添加处理器对于这些事件。一个blueprint的处理器将会运行,如果这个blueprint属于匹配这个请求的路径。
  1. 每个请求之前, before_request()函数被调用。如果这些函数当中的任一个返回一个值,其他的函数被跳过。这个返回值被当作响应,视图函数不再调用。
  2. 如果 before_request()函数没有返回一个响应,匹配路由的视图函数被调用然后返回一个响应。
  3. 视图函数的返回值被转换成一个实际的response object 并传递给after_request()函数。每个函数返回一个被改进的或新的response object.
  4. response 返回之后,上下文被出栈,调用teardown_request()和teardown_appcontext()函数。这些函数被调用尽管上面那些步骤抛出一个未处理的异常。
如果一个异常在teardown函数之前被抛出,Flask尝试使用errorhandler()匹配它来处理异常和返回一个响应。如果没有发现error handler,或者handler本身抛出一个异常,Flask 返回一个通用的(generic)的500 Internal Server Error响应。teardown函数仍然被调用,并被传递给异常对象。
如果启动debug 模式,未处理的异常不会被转换成500响应而是传播给WSGI 服务器。这允许开发服务器展示对应的debugger with traceback.
6.5 Teardown Callbacks teardown callbacks是独立与请求调度的,当context被出栈时调用。函数被调用尽管有一个未处理的异常在调配期间,手动入栈一个上下文。这意味着没有保证任何其他请求调度先执行。确保写这些函数以一种不依赖其他回调的方式并且不会失败。
在测试期间,他可以很有用对于推迟上下文出栈,这样他们的数据可以被其他测试函数访问。使用test_client()作为一个with 块保护上下文直到with 块 退出。
7 Config 关于Flask的官config, 官方文档
写得很好。

    推荐阅读