手动推送情境
如果尝试访问请求或在请求上下文之外使用它的任何内容,将收到以下错误消息:
RuntimeError: Working outside of request context.
这通常只在测试代码期望一个活动请求时发生。一个选项是使用测试客户端来模拟完整的请求。或者可以在block_request_Context()中使用test,块中运行的所有内容都可以访问请求并填写测试数据。:
def generate_report(year):
format = request.args.get('format')
...
with app.test_request_context(
'/make_report/2017', data={'format': 'short'}):
generate_report()
如果在代码中的其他地方看到与测试无关的错误,则表明应该将代码移到视图函数。
拆解回调
拆除回调与请求分派无关,但在情况弹出时由情况调用。即使在调度过程中存在未处理的异常和手动推送场景,也会调用这些函数。这意味着不能保证请求调度的任何其他部分将首先运行。确保以不依赖于其他回调且不会失败的方式编写这些函数。 在测试过程中,延迟请求的结束和弹出场景非常有用,以便可以在测试功能中访问它们的数据。在withblock_Client()中使用test保存情况,直到withblock结束。
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello():
print('during view')
return 'Hello, World!'
@app.teardown_request
def show_teardown(exception):
print('after with block')
with app.test_request_context():
print('during with block')
# teardown functions are called after the context with block exits
with app.test_client() as client:
client.get('/')
# the contexts are not popped even though the request ended
print(request.path)
# the contexts are popped and teardown functions are called after
# the client with block exists
测试 JSON API
Flask非常支持JSON,是创建JSON API的热门选择。使用JSON生成请求并检查响应中的JSON数据非常方便:
from flask import request, jsonify
@app.route('/api/auth')
def auth():
json_data = request.get_json()
email = json_data['email']
password = json_data['password']
return jsonify(token=generate_token(email, password))
with app.test_client() as c:
rv = c.post('/api/auth', json={
'email': '[email protected]', 'password': 'secret'
})
json_data = rv.get_json()
assert verify_token(email, json_data['token'])
在测试客户端方法中传递json参数,将请求数据设置为json序列化对象,并将内容类型设置为application/json。可以使用get_Json从请求或响应中获取Json数据。
静态文件
动态web应用程序还需要静态文件,通常是CSS和JavaScript文件。
理想情况下,服务器已经配置为为提供静态文件服务。
然而,Flask也可以在开发过程中做得很好。
只需在包或模块旁边创建一个名为static的文件夹。静态文件位于应用程序的/static中。使用特定的“静态”端点生成相应的URL
url_for('static', filename='style.css')
这个静态文件在文件系统中的位置应该是 static/style.css
。
Cookies
要访问cookies,可以使用cookies属性。
可以使用响应对象_ Cookie方法的集合来设置Cookie。
请求对象的cookie属性是一个包含客户端传输的所有cookie的字典。在Flask中,如果使用会话,则不应直接使用cookies,因为会话更安全。 阅读cookies:
from flask import request
@app.route('/')
def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
储存 cookies:
from flask import make_response
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
请注意,cookies是在响应对象上设置的。通常,只从视图函数返回字符串,Flask会将它们转换为响应对象。如果要显式转换,可以使make_Theresponse()函数,然后修改它。使用延迟请求回调方案,可以设置没有响应对象的cookie。
流内容
有时,需要将大量数据传输到客户端,而不需要将其保存在内存中。
想将操作中生成的数据直接发送到客户端而不通过文件系统时,应该怎么办? 答案是使用生成器和直接响应。
from flask import Response
@app.route('/large.csv')
def generate_large_csv():
def generate():
for row in iter_all_rows():
yield ','.join(row) + '\n'
return Response(generate(), mimetype='text/csv')
上面示例的技巧是从Jinja2环境中获取应用的模板对象,调用stream()而不是render(),并返回stream对象而不是字符串。
from flask import Response
def stream_template(template_name, **context):
app.update_template_context(context)
t = app.jinja_env.get_template(template_name)
rv = t.stream(context)
rv.enable_buffering(5)
return rv
@app.route('/my-large-page.html')
def render_large_template():
rows = iter_all_rows()
return Response(stream_template('the_template.html', rows=rows))
由于我们绕过Flask的模板渲染函数并使用模板对象本身,所以我们需要调用update_template_Context()来确保渲染的内容得到更新。
通过这种方式,模板遍历流内容。由于每次生成内容时服务器都会将内容发送给客户端,因此可能需要缓存来保存内容。我们使用了rvenable_Buffering(大小)。5是合理的违约。
访问和修改会话
with app.test_client() as c:
rv = c.get('/')
assert flask.session['foo'] == 42
但是,在发出请求之前,此方法无法修改会话或访问会话。
自Flask 0.8以来,我们提供了“会话处理”来在测试环境中打开和修改会话。
最后,会话被保存并准备好由客户端进行测试。处理的会话独立于后端实际使用的会话:
with app.test_client() as c:
with c.session_transaction() as sess:
sess['a_key'] = 'a value'
# once this is reached the session was stored and ready to be used by the client
c.get(...)